diff --git a/README.md b/README.md index 50fd6c78..b8cfb262 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ allprojects { In your application `build.gradle` file, add: ```groovy -def uport_sdk_version = "v0.4.2" +def uport_sdk_version = "v0.5.0" dependencies { //... // core SDK @@ -62,7 +62,8 @@ override fun onCreate() { ### defaultAccount -This preview version of the SDK has the concept of `defaultAccount` as a nullable field in the `Uport` object. +This preview version of the SDK has the concept of `defaultAccount` as a nullable field in the +`Uport` object. If there is no default account when a new one is created, it becomes the default. ```kotlin @@ -94,18 +95,20 @@ if (Uport.defaultAccount == null) { } ``` -In case the app gets killed during the account creation process, the `createAccount` method will try to resume the process where it left off. -It can be instructed to start from scratch, but that may cost additional fuel. +In case the app gets killed during the account creation process, the `createAccount` method will +try to resume the process where it left off. It can be instructed to start from scratch, but that +may cost additional fuel. ### Account management `Account` objects have a `handle` field that can be used to refer to them in the future. -The handle right now is an ethereum address but it should be treated as an opaque string, as it will change in a future release. -You should not send funds to that address. +The handle right now is an ethereum address but it should be treated as an opaque string, +as it will change in a future release. You should not send funds to that address. ### Key management -The `signer` library is used to create and manage keys for uport accounts. Read full details in [key management documentation](./docs/overview/key_management.md) +The `signer` library is used to create and manage keys for uport accounts. +Read full details in [key management documentation](./docs/overview/key_management.md) ### Ethereum interaction @@ -143,7 +146,7 @@ val receipt = Networks.rinkeby.awaitConfirmation(txHash) ### off-chain interaction -Off-chain interaction is essentially signing and verifying JWTs using uport-specific JWT algorithms. +Off-chain interaction is essentially signing and verifying JWTs using specific JWT algorithms. Verification of such tokens implies resolving a [Decentralized Identity (DID) document](https://github.com/uport-project/specs/blob/develop/pki/diddocument.md) that will contain the keys or address that should match a JWT signature. @@ -194,7 +197,7 @@ val jwt : String = JWTTools().create(payload, issuer, signer) ```kotlin //compute an encryption publicKey starting from a private key (can be an ethereum private key) -val publicKey = Crypto.getEncryptionPublicKey(privateKeyBytes). +val publicKey = Crypto.getEncryptionPublicKey(privateKeyBytes) //encrypt a message with an intended recipient val encryptedBundle = Crypto.encrypt("hello world", recipientPublicKeyBase64) @@ -209,19 +212,34 @@ val decryptedMessage = Crypto.decrypt(receivedBundle, recipientSecretKey) ## Dependencies -This library uses [kethereum](https://github.com/walleth/kethereum) for a lot of ethereum related work. +* These libraries use [KEthereum](https://github.com/komputing/KEthereum) for a lot of the ethereum related work. +* The smart-contract binding code is generated using [bivrost-kotlin](https://github.com/gnosis/bivrost-kotlin) +* The off-chain/JWT interactions rely on [kotlin-did-jwt](https://github.com/uport-project/kotlin-did-jwt) +* Protected Key management is done by [uport-android-signer](https://github.com/uport-project/uport-android-signer) -The smart-contract binding code is generated using [bivrost-kotlin](https://github.com/gnosis/bivrost-kotlin) Currently there is a transient dependency on [spongycastle](https://rtyley.github.io/spongycastle/) -but that may be removed when pure kotlin implementations of the required cryptographic primitives become available. +but that may be removed when pure kotlin implementations of the required cryptographic +primitives become available. ## Contributing -Want to contribute to uport-android-sdk? Cool, please read our [contribution guidelines](./docs/guides/CONTRIBUTING.md) to get an understanding of the process we use for making changes to this repo. +Want to contribute to uport-android-sdk? Cool, please read our +[contribution guidelines](./docs/guides/CONTRIBUTING.md) to get an understanding of the process +we use for making changes to this repo. ## Changelog +* 0.5.0 + * [breaking][bugfix] align JWT signature to spec (#93) + * [breaking][support] externalized did-jwt and signer modules (#97) + * [breaking][feature]`Account` is now an interface and the default implementation used is `HDAccount` (#89) + * [feature] easier configuration of JsonRPC endpoints (#91) + * [feature] add `verifyDisclosure()` method (#96) + * [feature] add `authenticateDisclosureResponse()` (#98) + * [feature] add W3C methods to create Verifiable Credential and Presentation (#100) + * [support] reduce UI test flakyness (#92) + * 0.4.2 * updated infura JsonRPC endpoint URLs. To avoid sudden disconnect you are strongly encouraged to use your own project on diff --git a/build.gradle b/build.gradle index 14012a52..68cf3210 100644 --- a/build.gradle +++ b/build.gradle @@ -3,12 +3,11 @@ buildscript { ext { + kotlin_version = '1.3.41' + kotlin_serialization_version = '0.11.0' + coroutines_version = "1.2.1" - kotlin_version = '1.3.21' - kotlin_serialization_version = '0.10.0' - coroutines_version = "1.1.1" - - android_tools_version = '3.3.1' + android_tools_version = '3.4.2' build_tools_version = "28.0.3" @@ -18,6 +17,7 @@ buildscript { support_lib_version = "28.0.0" play_services_version = "15.0.0" + firebase_iid_version = "17.1.2" test_runner_version = "1.0.2" test_rules_version = test_runner_version @@ -27,20 +27,22 @@ buildscript { mockito_version = "2.23.0" mockito_kotlin_version = "2.0.0" robolectric_version = "4.1" - mockk_version = "1.9" - assertk_version = "0.12" + mockk_version = "1.9.2" + assertk_version = "0.14" detekt_version = "1.0.0-RC14" moshi_version = "1.8.0" - okhttp_version = "3.10.0" + okhttp_version = "3.14.1" - bivrost_version = "1c0efeb7f3"//"v0.7.0" - kmnid_version = "0.2.1" - kethereum_version = "0.63" - khex_version = "0.5" + bivrost_version = "v0.7.1" + kmnid_version = "0.3.2" + kethereum_version = "0.75.1" tweetnacl_k_version = "0.0.1" + did_jwt_version = "0.3.1" + kotlin_common_version = "0.1.1" + uport_signer_version = "0.3.0" - uport_sdk_version = "v0.4.2" + uport_sdk_version = "v0.5.0" } repositories { @@ -95,14 +97,15 @@ allprojects { jcenter() maven { url 'https://jitpack.io' } maven { url "https://kotlin.bintray.com/kotlinx" } - mavenLocal() +// mavenLocal() } //address warnings about multiple kotlin runtimes in classpath configurations.all { + resolutionStrategy.dependencySubstitution { - substitute module("org.jetbrains.kotlin:kotlin-stdlib-jre7") because "warning about multiple runtimes in the classpath" with module("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") - substitute module("org.jetbrains.kotlin:kotlin-stdlib-jre8") because "warning about multiple runtimes in the classpath" with module("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") + substitute module("org.jetbrains.kotlin:kotlin-stdlib-jre7") because "warning about multiple runtimes in the classpath" with module("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version") + substitute module("org.jetbrains.kotlin:kotlin-stdlib-jre8") because "warning about multiple runtimes in the classpath" with module("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version") } resolutionStrategy.eachDependency { DependencyResolveDetails details -> @@ -114,6 +117,9 @@ allprojects { details.useVersion kotlin_version } } + + //XXX: this is needed until https://github.com/komputing/KEthereum/issues/65 is fixed + exclude group: "com.github.walleth" } } @@ -122,7 +128,23 @@ subprojects { subproject -> afterEvaluate { if (subproject.plugins.hasPlugin("com.android.application") || subproject.plugins.hasPlugin("com.android.library")) { - subproject.android.packagingOptions.exclude("META-INF/main.kotlin_module") + subproject.android { + packagingOptions { + exclude "META-INF/main.kotlin_module" + exclude "META-INF/atomicfu.kotlin_module" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + } + } + + subproject.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } } } } diff --git a/core/build.gradle b/core/build.gradle deleted file mode 100644 index 010678ad..00000000 --- a/core/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: "java-library" -apply plugin: "kotlin" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "core class definitions of the uPort android SDK" - -dependencies { - - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" - implementation "com.android.support:support-annotations:$support_lib_version" - - api "com.squareup.okhttp3:okhttp:$okhttp_version" - api "com.github.uport-project:kmnid:$kmnid_version" - api "com.github.walleth.kethereum:functions:$kethereum_version" - - testImplementation "junit:junit:$junit_version" - testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" -} \ No newline at end of file diff --git a/core/src/main/java/me/uport/sdk/core/CoroutineExtensions.kt b/core/src/main/java/me/uport/sdk/core/CoroutineExtensions.kt deleted file mode 100644 index c5a5c836..00000000 --- a/core/src/main/java/me/uport/sdk/core/CoroutineExtensions.kt +++ /dev/null @@ -1,21 +0,0 @@ -package me.uport.sdk.core - -import android.support.annotation.VisibleForTesting -import kotlinx.coroutines.Dispatchers -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext - -/** - * Shorthand for the UI thread that is also a mockable context in unit tests - */ -val UI by lazy { coroutineUiContextInitBlock() } - -private var coroutineUiContextInitBlock: () -> CoroutineContext = { Dispatchers.Main } - -/** - * Call this in @Before methods where you need to interact with UI context - */ -@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun stubUiContext() { - coroutineUiContextInitBlock = { EmptyCoroutineContext } -} \ No newline at end of file diff --git a/core/src/main/java/me/uport/sdk/core/Extensions.kt b/core/src/main/java/me/uport/sdk/core/Extensions.kt deleted file mode 100644 index 43056cd5..00000000 --- a/core/src/main/java/me/uport/sdk/core/Extensions.kt +++ /dev/null @@ -1,75 +0,0 @@ -@file:Suppress("unused") - -package me.uport.sdk.core - -import org.kethereum.extensions.toHexStringNoPrefix -import org.spongycastle.util.encoders.Base64 -import org.walleth.khex.clean0xPrefix -import org.walleth.khex.prepend0xPrefix -import java.math.BigInteger -import java.nio.charset.Charset -import kotlinx.coroutines.Dispatchers.Main as mainLooperContext - -//using spongy castle implementation because the android one can't be used properly in tests -/** - * Creates a base64 representation of the given byteArray, without padding - */ -fun ByteArray.toBase64(): String = Base64.toBase64String(this).replace("=", "") - -/** - * Creates a base64 representation of the byteArray that backs this string, without padding - */ -fun String.toBase64() = this.toByteArray().toBase64() - -/** - * pads a base64 string with a proper number of '=' - */ -fun String.padBase64() = this.padEnd(this.length + (4 - this.length % 4) % 4, '=') - -/** - * Converts the bytes of this string into a base64 string usable in a URL - */ -fun String.toBase64UrlSafe() = this.toBase64().replace('+', '-').replace('/', '_') - -/** - * Converts this byte array into a base64 string usable in a URL - */ -fun ByteArray.toBase64UrlSafe() = this.toBase64().replace('+', '-').replace('/', '_') - -/** - * Decodes a base64 string into a bytearray. - * Supports unpadded and url-safe strings as well. - */ -fun String.decodeBase64(): ByteArray = this - //force non-url safe and add padding so that it can be applied to all b64 formats - .replace('-', '+') - .replace('_', '/') - .padBase64() - .let { - if (it.isEmpty()) - byteArrayOf() - else - Base64.decode(it) - } - - -/** - * Converts a hex string to another hex string pre-padded with zeroes until it represents at least 32 bytes - */ -fun String.hexToBytes32() = clean0xPrefix().padStart(64, '0').prepend0xPrefix() - -/** - * Converts this BigInteger into a hex string that is represented by at least 32 bytes. - * The hex representation will be left-padded with zeroes if needed - */ -fun BigInteger.toBytes32String() = toHexStringNoPrefix().padStart(64, '0').prepend0xPrefix() - -/** - * shorthand to use the utf8 Charset - */ -val utf8: Charset = Charset.forName("UTF-8") - -/** - * interprets the underlying ByteArray as String - */ -fun ByteArray.bytes32ToString() = this.toString(utf8) \ No newline at end of file diff --git a/core/src/main/java/me/uport/sdk/core/HttpClient.kt b/core/src/main/java/me/uport/sdk/core/HttpClient.kt deleted file mode 100644 index 31f14e52..00000000 --- a/core/src/main/java/me/uport/sdk/core/HttpClient.kt +++ /dev/null @@ -1,76 +0,0 @@ -package me.uport.sdk.core - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okhttp3.MediaType -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody -import java.io.IOException - -/** - * Wraps common endpoint requests into suspend methods that also accept an optional bearer token - */ -@Suppress("StringLiteralDuplication") -class HttpClient { - - private val okClient by lazy { OkHttpClient() } - - /** - * Suspend method that does a HTTP POST with a a [jsonBody] to the given [url] - * and returns the response body as String or throws an Exception when failing - * Takes an optional [authToken] that will be sent as `Bearer` token on an `Authorization` header - * - * @throws [IOException] if the request could not be executed due to cancellation, disconnect or timeout - */ - suspend fun urlPost(url: String, jsonBody: String, authToken: String? = null): String { - val contentType = MediaType.parse("application/json") - - val body = RequestBody.create(contentType, jsonBody) - val request = Request.Builder().apply { - url(url) - addHeader("Accept", "application/json") - addHeader("Content-Type", "application/json") - if (authToken != null) { - addHeader("Authorization", "Bearer $authToken") - } - post(body) - }.build() - - val response = okClient.newCall(request).execute() - ?: throw IOException("got a null reply from server") - if (response.isSuccessful) { - return withContext(Dispatchers.IO) { response.body()?.string() } - ?: throw IOException("got a null response body") - } else { - val code = response.code() - throw IOException("server responded with HTTP $code") - } - } - - /** - * Suspend method that does a HTTP GET with given [url] and returns the response body as string or an exception - * Takes an optional [authToken] that will be sent as `Bearer` token on an `Authorization` header - * - * @throws [IOException] if the request could not be executed due to cancellation, disconnect or timeout. - */ - suspend fun urlGet(url: String, authToken: String? = null): String { - val request = Request.Builder().apply { - url(url) - addHeader("Accept", "application/json") - if (authToken != null) { - addHeader("Authorization", "Bearer $authToken") - } - }.build() - - val response = okClient.newCall(request).execute() - ?: throw IOException("got a null reply from server") - if (response.isSuccessful) { - return withContext(Dispatchers.IO) { response.body()?.string() } - ?: throw IOException("got a null response body") - } else { - val code = response.code() - throw IOException("server responded with HTTP $code") - } - } -} \ No newline at end of file diff --git a/core/src/main/java/me/uport/sdk/core/IFuelTokenProvider.kt b/core/src/main/java/me/uport/sdk/core/IFuelTokenProvider.kt deleted file mode 100644 index e7271845..00000000 --- a/core/src/main/java/me/uport/sdk/core/IFuelTokenProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -package me.uport.sdk.core - -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -/** - * Provides a fuel token given a device address. The fuel token is used in a meta-transaction context - */ -interface IFuelTokenProvider { - fun onCreateFuelToken(deviceAddress: String, callback: (err: Exception?, fuelToken: String) -> Unit) -} - -/** - * suspend wrapper for using a fuel token provider in coroutine contexts - */ -suspend fun IFuelTokenProvider.onCreateFuelToken(deviceAddress: String): String = suspendCoroutine { - this.onCreateFuelToken(deviceAddress) { err, fuelToken -> - if (err != null) { - it.resumeWithException(err) - } else { - it.resume(fuelToken) - } - } -} diff --git a/core/src/main/java/me/uport/sdk/core/ITimeProvider.kt b/core/src/main/java/me/uport/sdk/core/ITimeProvider.kt deleted file mode 100644 index 52aef6ed..00000000 --- a/core/src/main/java/me/uport/sdk/core/ITimeProvider.kt +++ /dev/null @@ -1,22 +0,0 @@ -package me.uport.sdk.core - -/** - * An interface for getting "current" timestamp. - * - * The default implementation is [SystemTimeProvider] but other implementations may be used during testing and for "was valid at" scenarios. - */ -interface ITimeProvider { - /** - * Returns the current timestamp in milliseconds - * @return the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC. - */ - fun nowMs(): Long -} - - -/** - * Default time provider - */ -object SystemTimeProvider : ITimeProvider { - override fun nowMs() = System.currentTimeMillis() -} \ No newline at end of file diff --git a/core/src/main/java/me/uport/sdk/core/Networks.kt b/core/src/main/java/me/uport/sdk/core/Networks.kt deleted file mode 100644 index ea338437..00000000 --- a/core/src/main/java/me/uport/sdk/core/Networks.kt +++ /dev/null @@ -1,127 +0,0 @@ -@file:Suppress("unused") - -package me.uport.sdk.core - -import me.uport.mnid.MNID -import org.walleth.khex.clean0xPrefix -import org.walleth.khex.prepend0xPrefix - -/** - * Convenience singleton that holds URLs and addresses for different eth networks. - * - * use the `registerNetwork` method to override defaults - */ -object Networks { - - private const val defaultFaucetUrl = "https://sensui.uport.me/api/v1/fund/" - private const val defaultTxRelayUrl = "https://sensui.uport.me/api/v2/relay/" - private const val mainnetId = "0x1" - private const val ropstenId = "0x3" - private const val rinkebyId = "0x4" - private const val kovanId = "0x2a" - private val NETWORK_CONFIG = emptyMap().toMutableMap() - - init { - registerNetwork(EthNetwork( - "mainnet", - mainnetId, - MNID.encode(mainnetId, "0xab5c8051b9a1df1aab0149f8b0630848b7ecabf6"), - "https://mainnet.infura.io/v3/e72b472993ff46d3b5b88faa47214d7f", - "https://etherscan.io", - defaultFaucetUrl, - defaultTxRelayUrl, - "0xec2642cd5a47fd5cca2a8a280c3b5f88828aa578")) - registerNetwork(EthNetwork( - "rinkeby", - rinkebyId, - MNID.encode(rinkebyId, "0x2cc31912b2b0f3075a87b3640923d45a26cef3ee"), - "https://rinkeby.infura.io/v3/e72b472993ff46d3b5b88faa47214d7f", - "https://rinkeby.etherscan.io", - "https://api.uport.me/sensui/fund/", - "https://api.uport.me/sensui/relay/", - "0xda8c6dce9e9a85e6f9df7b09b2354da44cb48331")) - registerNetwork(EthNetwork( - "ropsten", - ropstenId, - MNID.encode(ropstenId, "0x41566e3a081f5032bdcad470adb797635ddfe1f0"), - "https://ropsten.infura.io/v3/e72b472993ff46d3b5b88faa47214d7f", - "https://ropsten.io", - defaultFaucetUrl, - defaultTxRelayUrl, - "0xa5e04cf2942868f5a66b9f7db790b8ab662039d5")) - registerNetwork(EthNetwork( - "kovan", - kovanId, - MNID.encode(kovanId, "0x5f8e9351dc2d238fb878b6ae43aa740d62fc9758"), - "https://kovan.infura.io/v3/e72b472993ff46d3b5b88faa47214d7f", - "https://kovan.etherscan.io", - defaultFaucetUrl, - defaultTxRelayUrl, - "0xa9235151d3afa7912e9091ab76a36cbabe219a0c")) - } - - /** - * shorthand for getting the configuration for ETH mainnet (equivalent with Networks.get("0x1")) - */ - val mainnet - get() = get(mainnetId) - - /** - * shorthand for getting the configuration for rinkeby test network (equivalent with Networks.get("0x4")) - */ - val rinkeby - get() = get(rinkebyId) - - /** - * shorthand for getting the configuration for the ropsten test network (equivalent with Networks.get("0x3")) - */ - val ropsten - get() = get(ropstenId) - - /** - * shorthand for getting the configuration for the kovan test network (equivalent with Networks.get("0x2a")) - */ - val kovan - get() = get(kovanId) - - /** - * Register an ETH network configuration. - * This overrides any previously registered network with the same `networkId` - */ - fun registerNetwork(network: EthNetwork) { - val normalizedId = cleanId(network.networkId) - - //TODO: check if [network] has necessary fields - NETWORK_CONFIG[normalizedId] = network - } - - /** - * Gets an [EthNetwork] based on a [networkId] - */ - fun get(networkId: String): EthNetwork { - val cleanNetId = cleanId(networkId) - return NETWORK_CONFIG[cleanNetId] - ?: NETWORK_CONFIG[networkId] - ?: throw IllegalStateException("network [$networkId] not configured") - } - - private fun cleanId(id: String) = id.clean0xPrefix().trimStart('0').prepend0xPrefix() - -} - -/** - * A class that encapsulates the endpoints and metadata related to a particular ETH network - */ -data class EthNetwork( - val name: String, // ex: "kovan" - val networkId: String, // ex: "0x2a" - val registry: String, // ex: MNID.encode({address: '0x5f8e9351dc2d238fb878b6ae43aa740d62fc9758', network: '0x2a'}) - val rpcUrl: String, // ex: "https://kovan.infura.io/uport" - val explorerUrl: String = "", // ex: "https://kovan.etherscan.io" - val faucetUrl: String = "", // ex: "https://sensui.uport.me/api/v1/fund/" - val relayUrl: String = "", // ex: "https://sensui.uport.me/api/v2/relay/" - val txRelayAddress: String = "" -) - - - diff --git a/core/src/test/java/me/uport/sdk/core/ExtensionsKtTest.kt b/core/src/test/java/me/uport/sdk/core/ExtensionsKtTest.kt deleted file mode 100644 index fb538c69..00000000 --- a/core/src/test/java/me/uport/sdk/core/ExtensionsKtTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -@file:Suppress("ReplaceCallWithBinaryOperator") - -package me.uport.sdk.core - -import assertk.assert -import assertk.assertions.isEqualTo -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext -import org.junit.Before -import org.junit.Test - -class ExtensionsKtTest { - - @Before - fun `run before every test`() { - stubUiContext() - } - - @Test - fun `can use stubbed UI context in unit test`() { - - suspend fun whatever(): String = withContext(UI) { "hello world" } - - runBlocking { - assert(whatever()).isEqualTo("hello world") - } - } - - @Test - fun `base 64 works both ways`() { - val strings = listOf( - "", - "f", - "fo", - "foo", - "foo ", - "foo b", - "foo ba", - "foo bar", - "foo bar ", - "foo bar b", - "foo bar ba", - "foo bar baz" - ) - strings.forEach { - assert(String(it.toBase64().decodeBase64())).isEqualTo(it) - assert(it.toBase64().decodeBase64()).isEqualTo(it.toByteArray()) - assert(it.toBase64UrlSafe().decodeBase64()).isEqualTo(it.toByteArray()) - } - - val bytes = ByteArray(255) { it.toByte() } - for (i in 0..bytes.size) { - val tested = bytes.copyOfRange(0, i) - assert(tested.toBase64().decodeBase64()).isEqualTo(tested) - assert(tested.toBase64UrlSafe().decodeBase64()).isEqualTo(tested) - } - } -} \ No newline at end of file diff --git a/core/src/test/java/me/uport/sdk/core/TimeProviderTest.kt b/core/src/test/java/me/uport/sdk/core/TimeProviderTest.kt deleted file mode 100644 index 476a70e4..00000000 --- a/core/src/test/java/me/uport/sdk/core/TimeProviderTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package me.uport.sdk.core - -import assertk.assert -import assertk.assertions.isLessThan -import org.junit.Test - -class TimeProviderTest { - - @Test - fun `default provider is close to current time`() { - val systemTime = System.currentTimeMillis() - val defaultProvider = SystemTimeProvider - //some systems have tens of milliseconds as the lowest granularity - assert(defaultProvider.nowMs()).isLessThan(100L + systemTime) - } -} \ No newline at end of file diff --git a/credentials/build.gradle b/credentials/build.gradle index 0fea2bb4..37d03b2e 100644 --- a/credentials/build.gradle +++ b/credentials/build.gradle @@ -1,52 +1,21 @@ -apply plugin: "com.android.library" -apply plugin: "kotlin-android" +apply plugin: "kotlin" +apply plugin: "java-library" apply plugin: "kotlinx-serialization" apply plugin: "com.github.dcendents.android-maven" apply plugin: "com.jfrog.bintray" project.ext.description = "tools for creating, requesting, and verifying signed claims" -android { - compileSdkVersion compile_sdk_version - buildToolsVersion build_tools_version - - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - multiDexEnabled true - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - dexOptions { - jumboMode true - } - -} - dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + //noinspection DifferentStdlibGradleVersion + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "com.android.support:support-annotations:$support_lib_version" - api project(":serialization") - api project(":jwt") - api project(":universal-did") - api project(":signer") + api "com.github.uport-project.kotlin-did-jwt:jwt:$did_jwt_version" testImplementation "junit:junit:$junit_version" testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" - testImplementation project(":test-helpers") + testImplementation "io.mockk:mockk:$mockk_version" + testImplementation "com.github.uport-project.kotlin-common:test-helpers:$kotlin_common_version" } \ No newline at end of file diff --git a/credentials/src/main/AndroidManifest.xml b/credentials/src/main/AndroidManifest.xml deleted file mode 100644 index 75552dbe..00000000 --- a/credentials/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/credentials/src/main/java/me/uport/sdk/credentials/Credentials.kt b/credentials/src/main/java/me/uport/sdk/credentials/Credentials.kt index 3d982721..3ffebc8d 100644 --- a/credentials/src/main/java/me/uport/sdk/credentials/Credentials.kt +++ b/credentials/src/main/java/me/uport/sdk/credentials/Credentials.kt @@ -1,14 +1,17 @@ package me.uport.sdk.credentials -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PRIVATE -import com.uport.sdk.signer.Signer -import me.uport.mnid.MNID import me.uport.sdk.core.ITimeProvider import me.uport.sdk.core.SystemTimeProvider +import me.uport.sdk.credentials.model.CredentialParams +import me.uport.sdk.credentials.model.PresentationParams +import me.uport.sdk.jwt.InvalidJWTException import me.uport.sdk.jwt.JWTTools import me.uport.sdk.jwt.JWTTools.Companion.DEFAULT_JWT_VALIDITY_SECONDS -import me.uport.sdk.jwt.model.JwtHeader +import me.uport.sdk.jwt.JWTUtils.Companion.normalizeKnownDID +import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K +import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K_R +import me.uport.sdk.jwt.model.JwtPayload +import me.uport.sdk.signer.Signer /** * The [Credentials] class should allow you to create the signed payloads used in uPort including @@ -16,9 +19,9 @@ import me.uport.sdk.jwt.model.JwtHeader * for user data). It should also provide signature verification over signed payloads. */ class Credentials( - private val did: String, - private val signer: Signer, - private val clock: ITimeProvider = SystemTimeProvider + private val did: String, + private val signer: Signer, + private val clock: ITimeProvider = SystemTimeProvider ) { /** @@ -60,8 +63,10 @@ class Credentials( */ suspend fun createPersonalSignRequest(params: PersonalSignRequestParams): String { val payload = buildPayloadForPersonalSignReq(params) - return this.signJWT(payload, params.expiresInSeconds - ?: DEFAULT_PERSONAL_SIGN_REQ_VALIDITY_SECONDS) + return this.signJWT( + payload, + params.expiresInSeconds ?: DEFAULT_PERSONAL_SIGN_REQ_VALIDITY_SECONDS + ) } /** @@ -88,8 +93,10 @@ class Credentials( */ suspend fun createVerificationSignatureRequest(params: VerifiedClaimRequestParams): String { val payload = buildPayloadForVerifiedClaimReq(params) - return this.signJWT(payload, params.expiresInSeconds - ?: DEFAULT_VERIFIED_CLAIM_REQ_VALIDITY_SECONDS) + return this.signJWT( + payload, + params.expiresInSeconds ?: DEFAULT_VERIFIED_CLAIM_REQ_VALIDITY_SECONDS + ) } /** @@ -114,8 +121,10 @@ class Credentials( */ suspend fun createEthereumTransactionRequest(params: EthereumTransactionRequestParams): String { val payload = buildPayloadForEthereumTransactionReq(params) - return this.signJWT(payload, params.expiresInSeconds - ?: DEFAULT_ETHEREUM_TRANSACTION_REQ_VALIDITY_SECONDS) + return this.signJWT( + payload, + params.expiresInSeconds ?: DEFAULT_ETHEREUM_TRANSACTION_REQ_VALIDITY_SECONDS + ) } @@ -128,66 +137,223 @@ class Credentials( * @param callbackUrl **OPTIONAL** the URL that receives the response * @param expiresInSeconds **OPTIONAL** number of seconds of validity of the claim. * @param verifiedClaims **OPTIONAL** a list of verified claims which can be about anything - * related to the claim and in most cases it is related to the issuer + * related to the claim and in most cases it is related to the issuer * * ``` */ - suspend fun createVerification(sub: String, - claim: Map, - callbackUrl: String? = null, - verifiedClaims: Collection? = null, - expiresInSeconds: Long? = 600L): String { + suspend fun createVerification( + sub: String, + claim: Map, + callbackUrl: String? = null, + verifiedClaims: Collection? = null, + expiresInSeconds: Long? = 600L + ): String { val payload = mutableMapOf() payload["sub"] = sub payload["claim"] = claim payload["vc"] = verifiedClaims ?: emptyList() payload["callback"] = callbackUrl ?: "" + return this.signJWT(payload, expiresInSeconds ?: 600L) } + /** + * Creates a W3C compliant [verifiable credential](https://w3c.github.io/vc-data-model/#credentials) + * serialized as a JWT. + * + * @param subject the subject of the claim in the [credential] + * This becomes the `sub` field in the JWT + * @param credential the credential details; contains the claim being made about the [subject] + * This becomes the `vc` field in the JWT + * @param notValidBefore [**optional**] the UNIX timestamp that marks the beginning of the validity period. + * If this is not specified, the current timestamp is used as given by [clock] + * This becomes the `nbf` field of the JWT. It is measured in seconds. + * @param validityPeriod [**optional**] the number of seconds of validity of this credential. + * This influences the `exp` field in the JWT + * If this is negative, there will be no expiry date set on the credential. + * @param audience [**optional**] the intended audience of this credential. + * This results in the `aud` field of the JWT. If it is `null`, no audience will be set for the JWT. + * @param id [**optional**] the ID of this credential. + * This becomes the `jti` field in the resulting JWT. + */ + suspend fun createVerifiableCredential( + subject: String, + credential: CredentialParams, + notValidBefore: Long = clock.nowMs() / 1000L, + validityPeriod: Long = -1L, + audience: String? = null, + id: String? = null + ): String { + + val payload = mutableMapOf() + payload["sub"] = subject + + //add defaults if they are not set + val processedCredential = credential.copy( + context = credential.context.toMutableSet().apply { add("https://www.w3.org/2018/credentials/v1") }.toList(), + type = credential.type.toMutableSet().apply { add("VerifiableCredential") }.toList() + ) + + payload["vc"] = processedCredential + payload["nbf"] = notValidBefore + payload["iat"] = null + if (validityPeriod >= 0) { + val exp = notValidBefore + validityPeriod + payload["exp"] = exp + } + if (audience != null) { + payload["aud"] = audience + } + if (id != null) { + payload["jti"] = id + } + + return this.signJWT( + payload = payload, + expiresInSeconds = validityPeriod, + algorithm = ES256K + ) + } /** - * Creates a JWT using the given [payload], issued and signed using the [did] and [signer] - * fields of this [Credentials] instance. + * Creates a W3C compliant [verifiable presentation](https://w3c.github.io/vc-data-model/#presentations) + * serialized as a JWT. * - * @param payload a map detailing the payload of the resulting JWT - * @param expiresInSeconds _optional_ number of seconds of validity of the JWT. This parameter - * is ignored if the [payload] already contains an `exp` field + * @param vp encapsulates the core presentation parameters + * @param notValidBefore the `issuanceDate` as a unix timestamp (seconds). Defaults to the clock time + * (translates to `nbf` and `iat`) + * @param validityPeriod the number of seconds of validity of the resulting JWT. (influences `exp`) + * @param audience the intended audience of the resulting JWT (translates to `aud`) + * @param id an optional ID of the presentation (translates to `jti`) */ - suspend fun signJWT(payload: Map, expiresInSeconds: Long = DEFAULT_JWT_VALIDITY_SECONDS): String { - val normDID = normalizeKnownDID(this.did) - val alg = if (normDID.startsWith("did:uport:")) JwtHeader.ES256K else JwtHeader.ES256K_R - return JWTTools(clock).createJWT(payload, normDID, this.signer, expiresInSeconds = expiresInSeconds, algorithm = alg) + suspend fun createPresentation( + vp: PresentationParams, + notValidBefore: Long = clock.nowMs() / 1000L, + validityPeriod: Long = -1L, + audience: String? = null, + id: String? = null + ): String { + val payload = mutableMapOf() + + val processedPresentation = vp.copy( + context = vp.context.toMutableSet().apply { add("https://www.w3.org/2018/credentials/v1") }.toList(), + type = vp.type.toMutableSet().apply { add("VerifiablePresentation") }.toList() + ) + payload["vp"] = processedPresentation + payload["nbf"] = notValidBefore + payload["iat"] = null + if (validityPeriod >= 0) { + val exp = notValidBefore + validityPeriod + payload["exp"] = exp + } + if (audience != null) { + payload["aud"] = audience + } + if (id != null) { + payload["jti"] = id + } + + return this.signJWT( + payload = payload, + expiresInSeconds = validityPeriod, + algorithm = ES256K + ) } - companion object { - /** - * Attempts to normalize a [potentialDID] to a known format. - * - * This will transform an ethereum address into an ethr-did and an MNID string into a uport-did - */ - @VisibleForTesting(otherwise = PRIVATE) - internal fun normalizeKnownDID(potentialDID: String): String { + /** + * Verify and return profile from a + * [Selective Disclosure Response JWT](https://github.com/uport-project/specs/blob/develop/messages/shareresp.md). + * + * @param token **REQUIRED** The JWT response token from a selective disclosure request + * + * @return a [UportProfile] object + */ + suspend fun verifyDisclosure(token: String): UportProfile { - //ignore if it's already a did - if (potentialDID.matches("^did:(.*)?:.*".toRegex())) - return potentialDID + val payload = JWTTools().verify(token, audience = this.did) - //match an ethereum address - "^(0[xX])*([0-9a-fA-F]{40})".toRegex().find(potentialDID)?.let { - val (_, hexDigits) = it.destructured - return "did:ethr:0x$hexDigits" - } + val valid = mutableListOf() + val invalid = mutableListOf() - //match an MNID - if (MNID.isMNID(potentialDID)) { - return "did:uport:$potentialDID" + payload.verified?.forEach { + try { + valid.add(JWTTools().verify(it, audience = this.did)) + } catch (e: InvalidJWTException) { + e.printStackTrace() + invalid.add(it) } + } - return potentialDID + val networkId = payload.net ?: JWTTools().decode(payload.req ?: "").second.net + + return UportProfile( + payload.iss, + networkId, + valid, + invalid, + payload.own?.get("email"), + payload.own?.get("name"), + JWTTools().decodeRaw(token).second + ) + } + + /** + * Authenticates [Selective Disclosure Response JWT](https://github.com/uport-project/specs/blob/develop/messages/shareresp.md) from uPort + * client as part of the [Selective Disclosure Flow](https://github.com/uport-project/specs/blob/develop/flows/selectivedisclosure.md). + * + * It Verifies and parses the given response token and verifies the challenge response flow. + * + * @param token **REQUIRED** a valid JWT response token + * @returns a verified [JwtPayload] + * @throws [JWTAuthenticationException] when the challenge is failed or when the request token is unavailable + * + */ + suspend fun authenticateDisclosure(token: String): JwtPayload { + val payload = JWTTools().verify(token, auth = true, audience = this.did) + + if (payload.req == null) { + throw JWTAuthenticationException("Challenge was not included in response") + } + + val challenge = JWTTools().verify(payload.req ?: "") + + if (challenge.iss != this.did) { + throw JWTAuthenticationException("Challenge issuer does not match current identity: ${challenge.iss} != ${this.did}") + } + + if (challenge.type != JWTTypes.shareReq.name) { + throw JWTAuthenticationException("Challenge payload type invalid: ${challenge.type}") } + + return payload + } + + + /** + * Creates a JWT using the given [payload], issued and signed using the [did] and [signer] + * fields of this [Credentials] instance. + * + * @param payload a map detailing the payload of the resulting JWT + * @param expiresInSeconds _optional_ number of seconds of validity of the JWT. This parameter + * is ignored if the [payload] already contains an `exp` field + */ + internal suspend fun signJWT( + payload: Map, + expiresInSeconds: Long = DEFAULT_JWT_VALIDITY_SECONDS, + algorithm: String? = null + ): String { + val normDID = normalizeKnownDID(this.did) + val alg = algorithm ?: if (normDID.startsWith("did:uport:")) ES256K else ES256K_R + return JWTTools(clock).createJWT( + payload, + normDID, + this.signer, + expiresInSeconds = expiresInSeconds, + algorithm = alg + ) } } + diff --git a/credentials/src/main/java/me/uport/sdk/credentials/JWTAuthenticationException.kt b/credentials/src/main/java/me/uport/sdk/credentials/JWTAuthenticationException.kt new file mode 100644 index 00000000..8c61d3ea --- /dev/null +++ b/credentials/src/main/java/me/uport/sdk/credentials/JWTAuthenticationException.kt @@ -0,0 +1,10 @@ +package me.uport.sdk.credentials + +import me.uport.sdk.jwt.InvalidJWTException + +/** + * Thrown when a JWT authentication fails invalid because the issuer in the response and request do not match, + * the request type is not `shareReq` + * the request token is not in the response token + */ +class JWTAuthenticationException(message: String) : InvalidJWTException(message) diff --git a/credentials/src/main/java/me/uport/sdk/credentials/JWTTypes.kt b/credentials/src/main/java/me/uport/sdk/credentials/JWTTypes.kt index cd5e19d9..77ff1e92 100644 --- a/credentials/src/main/java/me/uport/sdk/credentials/JWTTypes.kt +++ b/credentials/src/main/java/me/uport/sdk/credentials/JWTTypes.kt @@ -1,11 +1,8 @@ package me.uport.sdk.credentials -import android.support.annotation.Keep - /** * Supported (known) types of JWT requests/responses */ -@Keep @Suppress("EnumEntryName") enum class JWTTypes { /** diff --git a/credentials/src/main/java/me/uport/sdk/credentials/SelectiveDisclosureRequestParams.kt b/credentials/src/main/java/me/uport/sdk/credentials/SelectiveDisclosureRequestParams.kt index 38832177..93402007 100644 --- a/credentials/src/main/java/me/uport/sdk/credentials/SelectiveDisclosureRequestParams.kt +++ b/credentials/src/main/java/me/uport/sdk/credentials/SelectiveDisclosureRequestParams.kt @@ -2,7 +2,6 @@ package me.uport.sdk.credentials -import android.support.annotation.Keep import me.uport.sdk.credentials.RequestAccountType.devicekey import me.uport.sdk.credentials.RequestAccountType.general import me.uport.sdk.credentials.RequestAccountType.keypair @@ -64,7 +63,7 @@ class SelectiveDisclosureRequestParams( * * @see [RequestAccountType] */ - val accountType: RequestAccountType? = RequestAccountType.general, + val accountType: RequestAccountType? = general, /** * [**optional**] @@ -104,7 +103,6 @@ class SelectiveDisclosureRequestParams( * [Private Chain Account](https://github.com/uport-project/specs/blob/develop/messages/privatechain.md) * * [none] no account is returned */ -@Keep @Suppress("EnumEntryName") enum class RequestAccountType { general, diff --git a/credentials/src/main/java/me/uport/sdk/credentials/UportProfile.kt b/credentials/src/main/java/me/uport/sdk/credentials/UportProfile.kt new file mode 100644 index 00000000..ebc029cb --- /dev/null +++ b/credentials/src/main/java/me/uport/sdk/credentials/UportProfile.kt @@ -0,0 +1,54 @@ +package me.uport.sdk.credentials + +import me.uport.sdk.jwt.model.JwtPayload + + +/** + * This class is used to create a uPort profile + */ +data class UportProfile( + + /** + * DID associated with the uPort profile + */ + val did: String, + + + /** + * network id of Ethereum chain of identity + * eg. 0x4 for rinkeby. It defaults to 0x1 for mainnet. + */ + val networkId: String?, + + + /** + * A list of verified JWT payloads associated with this uPort profile + */ + val valid: Collection, + + + /** + * A list of invalid JWT tokens associated with this uPort profile + */ + val invalid: Collection, + + + /** + * The email on the uPort profile + */ + val email: String? = null, + + + /** + * The name on the uPort profile + */ + val name: String? = null, + + + /** + * [**optional**] + * This can hold extra fields for the uPort profile. + * Use this to provide any extra fields that are not covered by the current version of the SDK + */ + val extras: Map? = null +) \ No newline at end of file diff --git a/credentials/src/main/java/me/uport/sdk/credentials/model/CredentialParams.kt b/credentials/src/main/java/me/uport/sdk/credentials/model/CredentialParams.kt new file mode 100644 index 00000000..257f8db6 --- /dev/null +++ b/credentials/src/main/java/me/uport/sdk/credentials/model/CredentialParams.kt @@ -0,0 +1,39 @@ +package me.uport.sdk.credentials.model + +import kotlinx.serialization.Required +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import me.uport.sdk.jwt.model.ArbitraryMapSerializer + +/** + * Encapsulates the core fields of a w3c + * [verifiable credential](https://w3c.github.io/vc-data-model/#credentials) + */ +@Serializable +data class CredentialParams( + + /** + * The list of types that make up this presentation. + * By default a `VerifiableCredential` type is used if not explicitly set. + */ + @Required + @SerialName("type") + val type: List = emptyList(), + + /** + * The actual payload of the credential. + * This is a dictionary of arbitrary data. + */ + @Required + @SerialName("credentialSubject") + @Serializable(with = ArbitraryMapSerializer::class) + val credentialSubject: Map, + + /** + * The LD context hooks. + */ + @Required + @SerialName("@context") + val context: List = emptyList() + +) \ No newline at end of file diff --git a/credentials/src/main/java/me/uport/sdk/credentials/model/PresentationParams.kt b/credentials/src/main/java/me/uport/sdk/credentials/model/PresentationParams.kt new file mode 100644 index 00000000..27ef3b65 --- /dev/null +++ b/credentials/src/main/java/me/uport/sdk/credentials/model/PresentationParams.kt @@ -0,0 +1,35 @@ +package me.uport.sdk.credentials.model + +import kotlinx.serialization.Required +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Encapsulates the core fields of a w3c + * [verifiable presentation](https://w3c.github.io/vc-data-model/#presentations) + */ +@Serializable +data class PresentationParams( + + /** + * the list of credentials (in JWT representation) that make up this presentation. + */ + @Required + @SerialName("verifiableCredential") + val verifiableCredentials: List, + + /** + * The list of types that make up this presentation. + * By default a `VerifiablePresentation` type is used if not explicitly set. + */ + @Required + @SerialName("type") + val type: List = emptyList(), + + /** + * The LD context hooks. + */ + @Required + @SerialName("@context") + val context: List = emptyList() +) \ No newline at end of file diff --git a/credentials/src/test/java/me/uport/sdk/credentials/ConfigurableEndpointsTest.kt b/credentials/src/test/java/me/uport/sdk/credentials/ConfigurableEndpointsTest.kt new file mode 100644 index 00000000..cceff977 --- /dev/null +++ b/credentials/src/test/java/me/uport/sdk/credentials/ConfigurableEndpointsTest.kt @@ -0,0 +1,102 @@ +package me.uport.sdk.credentials + +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.spyk +import kotlinx.coroutines.runBlocking +import me.uport.sdk.core.HttpClient +import me.uport.sdk.ethrdid.EthrDIDResolver +import me.uport.sdk.jsonrpc.JsonRPC +import me.uport.sdk.jwt.JWTTools +import me.uport.sdk.testhelpers.TestTimeProvider +import me.uport.sdk.universaldid.UniversalDID +import me.uport.sdk.uportdid.UportDIDResolver +import org.junit.Test + +class ConfigurableEndpointsTest { + + @Test + fun `can override JsonRPC endpoint for uport did resolver`() = runBlocking { + + val replacementURL = "http://127.0.0.1:8545" + + val httpSpy = spyk(HttpClient()) + coEvery { httpSpy.urlPost(any(), any()) } returns + """{"jsonrpc":"2.0","id":1,"result":"0x807a7cb8b670125774d70cf94d35e2355bb18bb51cf604f376c9996057f92fbf"}""" + coEvery { httpSpy.urlGet(any()) } returns + """{"@context":"http://schema.org","@type":"Person","publicKey":"0x04e8989d1826cd6258906cfaa71126e2db675eaef47ddeb9310ee10db69b339ab960649e1934dc1e1eac1a193a94bd7dc5542befc5f7339845265ea839b9cbe56f","publicEncKey":"k8q5G4YoIMP7zvqMC9q84i7xUBins6dXGt8g5H007F0="}""" + + val rpc = JsonRPC(replacementURL, httpSpy) + val resolver = UportDIDResolver(rpc) + + resolver.resolve("did:uport:2ozs2ntCXceKkAQKX4c9xp2zPS8pvkJhVqC") + + coVerify { + httpSpy.urlPost(eq(replacementURL), any()) + } + } + + @Test + fun `can override JsonRPC endpoint for ethr did resolver`() = runBlocking { + + val privateRpcUrl = "http://127.0.0.1:8545" + val privateRegistry = "0x1234567890123456789012345678901234567890" + + val httpSpy = spyk(HttpClient()) + + //eth_call to get owner + coEvery { httpSpy.urlPost(any(), match { it.contains("0x8733d4e8") }) } returns + """{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000cf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed"}""" + //eth_call to get last changed + coEvery { httpSpy.urlPost(any(), match { it.contains("0xf96d0f9f") }) } returns + """{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000000"}""" + //get logs + coEvery { httpSpy.urlPost(any(), match { it.contains("eth_getLogs") }) } returns + """{"jsonrpc":"2.0","id":1,"result":[]}""" + + val rpc = spyk(JsonRPC(privateRpcUrl, httpSpy)) + val resolver = EthrDIDResolver(rpc, privateRegistry) + + resolver.resolve("did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed") + + coVerify { + httpSpy.urlPost(eq(privateRpcUrl), any()) + rpc.ethCall(eq(privateRegistry), any()) + rpc.getLogs(eq(privateRegistry), any(), any(), any()) + } + } + + @Test + fun `can override JsonRPC endpoint for JWT verification with ethr DID issuer`(): Unit = runBlocking { + val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbSI6eyJuYW1lIjoiQm9iIiwiZ2VuZGVyIjoibWFsZSJ9LCJpYXQiOjE1NDk5MDg0MjQsImV4cCI6MTU0OTkwODcyNCwiaXNzIjoiZGlkOmV0aHI6MHhjZjAzZGQwYTg5NGVmNzljYjViNjAxYTQzYzRiMjVlM2FlNGM2N2VkIn0.ffjGFzoSfX-fS50GHhYkwA8It5034Rw8BczWslUcbfGI51uJSGbmhfJSfeGdEaPlFFgVrnRj1YBoG_oHrnEiBQA" + + val privateRpcUrl = "http://127.0.0.1:8545" + val privateRegistry = "0x1234567890123456789012345678901234567890" + + val httpSpy = spyk(HttpClient()) + + //eth_call to get owner + coEvery { httpSpy.urlPost(any(), match { it.contains("0x8733d4e8") }) } returns + """{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000cf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed"}""" + //eth_call to get last changed + coEvery { httpSpy.urlPost(any(), match { it.contains("0xf96d0f9f") }) } returns + """{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000000"}""" + //get logs + coEvery { httpSpy.urlPost(any(), match { it.contains("eth_getLogs") }) } returns + """{"jsonrpc":"2.0","id":1,"result":[]}""" + + val rpc = spyk(JsonRPC(privateRpcUrl, httpSpy)) + val resolver = EthrDIDResolver(rpc, privateRegistry) + UniversalDID.registerResolver(resolver) + + JWTTools(TestTimeProvider(1549908724000)) + .verify(token) + + coVerify { + httpSpy.urlPost(eq(privateRpcUrl), any()) + } + + UniversalDID.clearResolvers() + } + +} \ No newline at end of file diff --git a/credentials/src/test/java/me/uport/sdk/credentials/CredentialsTest.kt b/credentials/src/test/java/me/uport/sdk/credentials/CredentialsTest.kt index 1e35dc26..23a01ca4 100644 --- a/credentials/src/test/java/me/uport/sdk/credentials/CredentialsTest.kt +++ b/credentials/src/test/java/me/uport/sdk/credentials/CredentialsTest.kt @@ -1,50 +1,31 @@ package me.uport.sdk.credentials -import assertk.assert -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThanOrEqualTo -import assertk.assertions.isNotNull -import com.uport.sdk.signer.KPSigner +import assertk.assertThat +import assertk.assertions.* +import io.mockk.coEvery +import io.mockk.spyk import kotlinx.coroutines.runBlocking +import me.uport.sdk.core.ITimeProvider import me.uport.sdk.core.SystemTimeProvider +import me.uport.sdk.credentials.model.PresentationParams +import me.uport.sdk.credentials.model.CredentialParams +import me.uport.sdk.ethrdid.EthrDIDDocument +import me.uport.sdk.ethrdid.EthrDIDResolver +import me.uport.sdk.jsonrpc.JsonRPC import me.uport.sdk.jwt.JWTTools import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K_R +import me.uport.sdk.signer.KPSigner import me.uport.sdk.testhelpers.TestTimeProvider +import me.uport.sdk.testhelpers.coAssert +import me.uport.sdk.universaldid.UniversalDID +import me.uport.sdk.uportdid.UportDIDDocument +import me.uport.sdk.uportdid.UportDIDResolver import org.junit.Test +import kotlin.math.floor class CredentialsTest { - @Test - fun `can normalize a known string format to a DID format`() { - val transformations = mapOf( - //already did - "did:example:something something" to "did:example:something something", - "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" to "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", - "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#keys-1" to "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#keys-1", - "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX" to "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX", - "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX#owner" to "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX#owner", - - //eth addr to ethrdid - "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" to "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", - "0XF3BEAC30c498d9e26865f34fcaa57dbb935b0d74" to "did:ethr:0xF3BEAC30c498d9e26865f34fcaa57dbb935b0d74", - "f3beac30c498d9e26865f34fcaa57dbb935b0d74" to "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", - - //mnid to uport did - "2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX" to "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX", - "5A8bRWU3F7j3REx3vkJWxdjQPp4tqmxFPmab1Tr" to "did:uport:5A8bRWU3F7j3REx3vkJWxdjQPp4tqmxFPmab1Tr", - - //unknown is left intact - "0x1234" to "0x1234", - "2nQtiQG6Cgm1GYTBaaK" to "2nQtiQG6Cgm1GYTBaaK" - ) - - transformations.forEach { (orig, expected) -> - assert(Credentials.normalizeKnownDID(orig)).isEqualTo(expected) - } - } - @Test fun `signJWT uses the correct algorithm for uport did`() = runBlocking { @@ -52,54 +33,110 @@ class CredentialsTest { val jwt = cred.signJWT(emptyMap()) val (header, _, _) = JWTTools().decode(jwt) - assert(header.alg).isEqualTo(ES256K) + assertThat(header.alg).isEqualTo(ES256K) } @Test fun `create verification test with all params`() = runBlocking { - val expectedJWT = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJjbGFpbSI6eyJuYW1lIjoiSm9obiBEb2UiLCJhZ2UiOiIzNSIsImxvY2F0aW9uIjoiR2VybWFueSJ9LCJ2YyI6WyJleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUprYVdRNlpYUm9jam93ZUdZelltVmhZek13WXpRNU9HUTVaVEkyT0RZMVpqTTBabU5oWVRVM1pHSmlPVE0xWWpCa056UWlMQ0psWkhWallYUnBiMjRpT2lKTllYTjBaWEp6SWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlEud1RuUGhnTWJyU2xyV2NmUjdfX3hXYmxHLUEzbmdqTFQyYlBfTTdaOW1pWSIsImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUp6ZFdJaU9pSmthV1E2WlhSb2Nqb3dlR1l6WW1WaFl6TXdZelE1T0dRNVpUSTJPRFkxWmpNMFptTmhZVFUzWkdKaU9UTTFZakJrTnpRaUxDSnNiMk5oZEdsdmJpSTZJbFJsZUdGeklpd2lhV0YwSWpveE5URTJNak01TURJeWZRLk8yb3FZNHBnbUFtV3FlT3Q3NlBUaUIzeTlqRUdmMlphWEVoSVJlTTlJTFUiXSwiY2FsbGJhY2siOiJteWFwcDovL2dldC1iYWNrLXRvLW1lLXdpdGgtcmVzcG9uc2UudXJsIiwiaWF0IjoxMjM0NTY3OCwiZXhwIjoxMjM0ODY3OCwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.aGy68_dqtXBi65MuDdwlVUHxJ4kBV_TjbHVKDPbyzYWyW-hCbBkO7AqLo3zN4ToiSOSZiWel4hl6p0HIBU9Hnw" + val expectedJWT = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJjbGFpbSI6eyJuYW1lIjoiSm9obiBEb2UiLCJhZ2UiOiIzNSIsImxvY2F0aW9uIjoiR2VybWFueSJ9LCJ2YyI6WyJleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUprYVdRNlpYUm9jam93ZUdZelltVmhZek13WXpRNU9HUTVaVEkyT0RZMVpqTTBabU5oWVRVM1pHSmlPVE0xWWpCa056UWlMQ0psWkhWallYUnBiMjRpT2lKTllYTjBaWEp6SWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlEud1RuUGhnTWJyU2xyV2NmUjdfX3hXYmxHLUEzbmdqTFQyYlBfTTdaOW1pWSIsImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUp6ZFdJaU9pSmthV1E2WlhSb2Nqb3dlR1l6WW1WaFl6TXdZelE1T0dRNVpUSTJPRFkxWmpNMFptTmhZVFUzWkdKaU9UTTFZakJrTnpRaUxDSnNiMk5oZEdsdmJpSTZJbFJsZUdGeklpd2lhV0YwSWpveE5URTJNak01TURJeWZRLk8yb3FZNHBnbUFtV3FlT3Q3NlBUaUIzeTlqRUdmMlphWEVoSVJlTTlJTFUiXSwiY2FsbGJhY2siOiJteWFwcDovL2dldC1iYWNrLXRvLW1lLXdpdGgtcmVzcG9uc2UudXJsIiwiaWF0IjoxMjM0NTY3OCwiZXhwIjoxMjM0ODY3OCwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.aGy68_dqtXBi65MuDdwlVUHxJ4kBV_TjbHVKDPbyzYWyW-hCbBkO7AqLo3zN4ToiSOSZiWel4hl6p0HIBU9Hnw" val claim = mapOf( - "name" to "John Doe", - "age" to "35", - "location" to "Germany" + "name" to "John Doe", + "age" to "35", + "location" to "Germany" ) val vc = listOf( - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJlZHVjYXRpb24iOiJNYXN0ZXJzIiwiaWF0IjoxNTE2MjM5MDIyfQ.wTnPhgMbrSlrWcfR7__xWblG-A3ngjLT2bP_M7Z9miY", - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJsb2NhdGlvbiI6IlRleGFzIiwiaWF0IjoxNTE2MjM5MDIyfQ.O2oqY4pgmAmWqeOt76PTiB3y9jEGf2ZaXEhIReM9ILU" + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJlZHVjYXRpb24iOiJNYXN0ZXJzIiwiaWF0IjoxNTE2MjM5MDIyfQ.wTnPhgMbrSlrWcfR7__xWblG-A3ngjLT2bP_M7Z9miY", + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJsb2NhdGlvbiI6IlRleGFzIiwiaWF0IjoxNTE2MjM5MDIyfQ.O2oqY4pgmAmWqeOt76PTiB3y9jEGf2ZaXEhIReM9ILU" ) val timeProvider = TestTimeProvider(12345678000L) val cred = Credentials("did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX", KPSigner("0x1234"), timeProvider) val jwt = cred.createVerification( - "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", - claim, - "myapp://get-back-to-me-with-response.url", - vc, - 3000L + "did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", + claim, + "myapp://get-back-to-me-with-response.url", + vc, + 3000L ) - assert(jwt).isEqualTo(expectedJWT) + assertThat(jwt).isEqualTo(expectedJWT) } @Test fun `create verification test with required params only`() = runBlocking { - val expectedJWT = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJjbGFpbSI6eyJuYW1lIjoiSm9obiBEb2UiLCJhZ2UiOiIzNSIsImxvY2F0aW9uIjoiR2VybWFueSJ9LCJ2YyI6W10sImNhbGxiYWNrIjoiIiwiaWF0IjoxMjM0NTY3OCwiZXhwIjoxMjM0NjI3OCwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.C5sY_WCnSjYmqX-w3NZo9AmB6qVUy-Uwd6Fzz24CtbK0JWAYxgslqr6-JYjkB5O5Eu9IJYNS-1pKH-waNGGwmA" + val expectedJWT = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJjbGFpbSI6eyJuYW1lIjoiSm9obiBEb2UiLCJhZ2UiOiIzNSIsImxvY2F0aW9uIjoiR2VybWFueSJ9LCJ2YyI6W10sImNhbGxiYWNrIjoiIiwiaWF0IjoxMjM0NTY3OCwiZXhwIjoxMjM0NjI3OCwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.C5sY_WCnSjYmqX-w3NZo9AmB6qVUy-Uwd6Fzz24CtbK0JWAYxgslqr6-JYjkB5O5Eu9IJYNS-1pKH-waNGGwmA" - val claim = mapOf("name" to "John Doe", - "age" to "35", - "location" to "Germany") + val claim = mapOf( + "name" to "John Doe", + "age" to "35", + "location" to "Germany" + ) val timeProvider = TestTimeProvider(12345678000L) val cred = Credentials("did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX", KPSigner("0x1234"), timeProvider) val jwt = cred.createVerification("did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", claim) - assert(jwt).isEqualTo(expectedJWT) + assertThat(jwt).isEqualTo(expectedJWT) + } + + @Test + fun `create basic verifiable credential`() = runBlocking { + + val signer = KPSigner("74894f8853f90e6e3d6dfdd343eb0eb70cca06e552ed8af80adadcc573b35da3") + val did = "did:ethr:${signer.getAddress()}" + + val cred = Credentials(did, signer, clock = object : ITimeProvider { + override fun nowMs() = 1485321133000L + }) + val jwt = cred.createVerifiableCredential( + subject = "did:ethr:0x12345678", + credential = CredentialParams( + context = listOf( + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ), + type = listOf( + "VerifiableCredential", "UniversityDegreeCredential" + ), + credentialSubject = mapOf( + "degree" to mapOf( + "type" to "BachelorDegree", + "name" to "Baccalauréat en musiques numériques" + ) + ) + ), + id = "http://example.edu/credentials/3732" + ) + + assertThat(jwt).isEqualTo("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweDEyMzQ1Njc4IiwidmMiOnsidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fSwiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy9leGFtcGxlcy92MSJdfSwibmJmIjoxNDg1MzIxMTMzLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsImlzcyI6ImRpZDpldGhyOjB4YmMzYWU1OWJjNzZmODk0ODIyNjIyY2RlZjdhMjAxOGRiZTM1Mzg0MCJ9.Af2by3Ar7ZOK-a_fkCYr45PZ81lXGKM2ruB0Io5loQJ9k48Qz8jt5eusiukxrxQRDFLHd4LBPSfzoMDNbAX72A") + } + + @Test + fun `create basic verifiable presentation`() = runBlocking { + + val signer = KPSigner("74894f8853f90e6e3d6dfdd343eb0eb70cca06e552ed8af80adadcc573b35da3") + val did = "did:ethr:${signer.getAddress()}" + + val cred = Credentials(did, signer, clock = object : ITimeProvider { + override fun nowMs() = 1485321133000L + }) + val presentation = cred.createPresentation( + PresentationParams( + verifiableCredentials = listOf("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJzdWIiOiJkaWQ6ZXRocjoweDEyMzQ1Njc4IiwidmMiOnsidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjY2FsYXVyw6lhdCBlbiBtdXNpcXVlcyBudW3DqXJpcXVlcyJ9fSwiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy9leGFtcGxlcy92MSJdfSwibmJmIjoxNDg1MzIxMTMzLCJpYXQiOjE0ODUzMjExMzMsImp0aSI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8zNzMyIiwiaXNzIjoiZGlkOmV0aHI6MHhiYzNhZTU5YmM3NmY4OTQ4MjI2MjJjZGVmN2EyMDE4ZGJlMzUzODQwIn0.W0TMJElntSsdxTIFZvDerihBY15e7jbRGs8dSo9pSmpwR67Xe83X7dY0WhuufADc06Cg2cxAk17ayLWQ7M2Vrw") + ) + ) + + assertThat(presentation).isEqualTo( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJ2cCI6eyJ2ZXJpZmlhYmxlQ3JlZGVudGlhbCI6WyJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5rc2lmUS5leUp6ZFdJaU9pSmthV1E2WlhSb2Nqb3dlREV5TXpRMU5qYzRJaXdpZG1NaU9uc2lkSGx3WlNJNld5SldaWEpwWm1saFlteGxRM0psWkdWdWRHbGhiQ0lzSWxWdWFYWmxjbk5wZEhsRVpXZHlaV1ZEY21Wa1pXNTBhV0ZzSWwwc0ltTnlaV1JsYm5ScFlXeFRkV0pxWldOMElqcDdJbVJsWjNKbFpTSTZleUowZVhCbElqb2lRbUZqYUdWc2IzSkVaV2R5WldVaUxDSnVZVzFsSWpvaVFtRmpZMkZzWVhWeXc2bGhkQ0JsYmlCdGRYTnBjWFZsY3lCdWRXM0RxWEpwY1hWbGN5SjlmU3dpUUdOdmJuUmxlSFFpT2xzaWFIUjBjSE02THk5M2QzY3Vkek11YjNKbkx6SXdNVGd2WTNKbFpHVnVkR2xoYkhNdmRqRWlMQ0pvZEhSd2N6b3ZMM2QzZHk1M015NXZjbWN2TWpBeE9DOWpjbVZrWlc1MGFXRnNjeTlsZUdGdGNHeGxjeTkyTVNKZGZTd2libUptSWpveE5EZzFNekl4TVRNekxDSnBZWFFpT2pFME9EVXpNakV4TXpNc0ltcDBhU0k2SW1oMGRIQTZMeTlsZUdGdGNHeGxMbVZrZFM5amNtVmtaVzUwYVdGc2N5OHpOek15SWl3aWFYTnpJam9pWkdsa09tVjBhSEk2TUhoaVl6TmhaVFU1WW1NM05tWTRPVFE0TWpJMk1qSmpaR1ZtTjJFeU1ERTRaR0psTXpVek9EUXdJbjAuVzBUTUpFbG50U3NkeFRJRlp2RGVyaWhCWTE1ZTdqYlJHczhkU285cFNtcHdSNjdYZTgzWDdkWTBXaHV1ZkFEYzA2Q2cyY3hBazE3YXlMV1E3TTJWcnciXSwidHlwZSI6WyJWZXJpZmlhYmxlUHJlc2VudGF0aW9uIl0sIkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl19LCJuYmYiOjE0ODUzMjExMzMsImlzcyI6ImRpZDpldGhyOjB4YmMzYWU1OWJjNzZmODk0ODIyNjIyY2RlZjdhMjAxOGRiZTM1Mzg0MCJ9.UeLoqTYxTdTs6fQ4RCc6vb-5hyujB1ioUc5cas_r4tLXYK5WX4QOm77rrUaTLD3M2HzOB_gsxzT75AmwWOVHWA" + ) } @Test @@ -109,54 +146,54 @@ class CredentialsTest { val jwt = cred.signJWT(emptyMap()) val (header, _, _) = JWTTools().decode(jwt) - assert(header.alg).isEqualTo(ES256K_R) + assertThat(header.alg).isEqualTo(ES256K_R) } @Test fun `selective disclosure request contains required fields`() = runBlocking { - val nowSeconds = Math.floor(SystemTimeProvider.nowMs() / 1000.0).toLong() + val nowSeconds = floor(SystemTimeProvider.nowMs() / 1000.0).toLong() val cred = Credentials("did:example:issuer", KPSigner("0x1234")) val jwt = cred.createDisclosureRequest(SelectiveDisclosureRequestParams(emptyList(), "")) val (_, payload, _) = JWTTools().decode(jwt) - assert(payload.iss).isEqualTo("did:example:issuer") - assert(payload.iat).isNotNull { - it.isGreaterThanOrEqualTo(nowSeconds) - } - assert(payload.type).isEqualTo(JWTTypes.shareReq.name) + assertThat(payload.iss).isEqualTo("did:example:issuer") + assertThat(payload.iat) + .isNotNull() + .isGreaterThanOrEqualTo(nowSeconds) + assertThat(payload.type).isEqualTo(JWTTypes.shareReq.name) } @Test fun `selective disclosure payload contains relevant fields`() = runBlocking { val params = SelectiveDisclosureRequestParams( - requested = listOf("name", "country"), - callbackUrl = "myapp://get-back-to-me-with-response.url", - verified = listOf("email"), - networkId = "0x4", - accountType = RequestAccountType.keypair, - vc = emptyList(), - expiresInSeconds = 1234L, - extras = mapOf( - "hello" to "world", - "type" to "expect this to be overwritten" - ) + requested = listOf("name", "country"), + callbackUrl = "myapp://get-back-to-me-with-response.url", + verified = listOf("email"), + networkId = "0x4", + accountType = RequestAccountType.keypair, + vc = emptyList(), + expiresInSeconds = 1234L, + extras = mapOf( + "hello" to "world", + "type" to "expect this to be overwritten" + ) ) val load = buildPayloadForShareReq(params) - assert((load["requested"] as List<*>).containsAll(listOf("name", "country"))) - assert((load["verified"] as List<*>).containsAll(listOf("email"))) + assertThat((load["requested"] as List<*>).containsAll(listOf("name", "country"))) + assertThat((load["verified"] as List<*>).containsAll(listOf("email"))) - assert(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") - assert(load["net"]).isEqualTo("0x4") - assert(load["act"]).isEqualTo("keypair") - assert(load["hello"]).isEqualTo("world") - assert(load["type"]).isEqualTo("shareReq") + assertThat(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") + assertThat(load["net"]).isEqualTo("0x4") + assertThat(load["act"]).isEqualTo("keypair") + assertThat(load["hello"]).isEqualTo("world") + assertThat(load["type"]).isEqualTo("shareReq") - assert((load["vc"] as List<*>)).isEmpty() + assertThat((load["vc"] as List<*>)).isEmpty() } @@ -164,29 +201,29 @@ class CredentialsTest { fun `personal sign request payload contains relevant fields`() = runBlocking { val params = PersonalSignRequestParams( - data = "sign this message", - callbackUrl = "myapp://get-back-to-me-with-response.url", - from = "0x1122334455667788990011223344556677889900", - riss = "did:ethr:0x1122334455667788990011223344556677889900", - networkId = "0x4", - vc = emptyList(), - expiresInSeconds = 1234L, - extras = mapOf( - "hello" to "world", - "type" to "expect this to be overwritten" - ) + data = "sign this message", + callbackUrl = "myapp://get-back-to-me-with-response.url", + from = "0x1122334455667788990011223344556677889900", + riss = "did:ethr:0x1122334455667788990011223344556677889900", + networkId = "0x4", + vc = emptyList(), + expiresInSeconds = 1234L, + extras = mapOf( + "hello" to "world", + "type" to "expect this to be overwritten" + ) ) val load = buildPayloadForPersonalSignReq(params) - assert(load["type"]).isEqualTo("personalSigReq") - assert(load["data"]).isEqualTo("sign this message") - assert(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") - assert(load["riss"]).isEqualTo("did:ethr:0x1122334455667788990011223344556677889900") - assert(load["from"]).isEqualTo("0x1122334455667788990011223344556677889900") - assert(load["net"]).isEqualTo("0x4") - assert((load["vc"] as List<*>)).isEmpty() - assert(load["hello"]).isEqualTo("world") + assertThat(load["type"]).isEqualTo("personalSigReq") + assertThat(load["data"]).isEqualTo("sign this message") + assertThat(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") + assertThat(load["riss"]).isEqualTo("did:ethr:0x1122334455667788990011223344556677889900") + assertThat(load["from"]).isEqualTo("0x1122334455667788990011223344556677889900") + assertThat(load["net"]).isEqualTo("0x4") + assertThat((load["vc"] as List<*>)).isEmpty() + assertThat(load["hello"]).isEqualTo("world") } @@ -194,33 +231,395 @@ class CredentialsTest { fun `verified claim request payload contains relevant fields`() = runBlocking { val params = VerifiedClaimRequestParams( - unsignedClaim = mapOf("name" to "John Doe"), - callbackUrl = "myapp://get-back-to-me-with-response.url", - riss = "did:ethr:0x1122334455667788990011223344556677889900", - rexp = 1234L, - aud = "did:ethr:0x9988776655443322110099887766554433221100", - sub = "did:ethr:0xFFEEDDCCBBAA9988776655443322110099887766", - issc = mapOf("dappName" to "testing"), - vc = emptyList(), - expiresInSeconds = 1234L, - extras = mapOf( - "hello" to "world", - "type" to "expect this to be overwritten" - ) + unsignedClaim = mapOf("name" to "John Doe"), + callbackUrl = "myapp://get-back-to-me-with-response.url", + riss = "did:ethr:0x1122334455667788990011223344556677889900", + rexp = 1234L, + aud = "did:ethr:0x9988776655443322110099887766554433221100", + sub = "did:ethr:0xFFEEDDCCBBAA9988776655443322110099887766", + issc = mapOf("dappName" to "testing"), + vc = emptyList(), + expiresInSeconds = 1234L, + extras = mapOf( + "hello" to "world", + "type" to "expect this to be overwritten" + ) ) val load = buildPayloadForVerifiedClaimReq(params) - assert(load["type"]).isEqualTo("verReq") - assert(load["unsignedClaim"]).isEqualTo(mapOf("name" to "John Doe")) - assert(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") - assert(load["riss"]).isEqualTo("did:ethr:0x1122334455667788990011223344556677889900") - assert((load["vc"] as List<*>)).isEmpty() - assert(load["hello"]).isEqualTo("world") - assert(load["aud"]).isEqualTo("did:ethr:0x9988776655443322110099887766554433221100") - assert(load["sub"]).isEqualTo("did:ethr:0xFFEEDDCCBBAA9988776655443322110099887766") - assert(load["issc"]).isEqualTo(mapOf("dappName" to "testing")) - assert(load["rexp"]).isEqualTo(1234L) + assertThat(load["type"]).isEqualTo("verReq") + assertThat(load["unsignedClaim"]).isEqualTo(mapOf("name" to "John Doe")) + assertThat(load["callback"]).isEqualTo("myapp://get-back-to-me-with-response.url") + assertThat(load["riss"]).isEqualTo("did:ethr:0x1122334455667788990011223344556677889900") + assertThat((load["vc"] as List<*>)).isEmpty() + assertThat(load["hello"]).isEqualTo("world") + assertThat(load["aud"]).isEqualTo("did:ethr:0x9988776655443322110099887766554433221100") + assertThat(load["sub"]).isEqualTo("did:ethr:0xFFEEDDCCBBAA9988776655443322110099887766") + assertThat(load["issc"]).isEqualTo(mapOf("dappName" to "testing")) + assertThat(load["rexp"]).isEqualTo(1234L) } -} \ No newline at end of file + @Test + @Suppress("UNCHECKED_CAST") + fun `can return uport profile from jwt payload`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "aud" to "did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed", + "net" to "0x4", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "verified" to listOf( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpc3MiOiIyb2VYdWZIR0RwVTUxYmZLQnNaRGR1N0plOXdlSjNyN3NWRyIsImlhdCI6MTU1NjcwMTA3NCwiZXhwIjoxNzIwMzY2NDMyLCJuZXQiOiIweDQiLCJ0eXBlIjoic2hhcmVSZXEifQ.PjsCopgtHxfTkGrQUT1ID7P8bfXyeCZoy0GnHw5p8xv6mJYDE9MAVQK6sjEivXyOQhb2bWs4Pm9vWl4dFEhpGwE", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbXMiOnsibmFtZSI6IlIgRGFuZWVsIE9saXZhdyJ9LCJpYXQiOjEyMzQ1Njc4LCJleHAiOjEyMzQ1OTc4LCJpc3MiOiJkaWQ6ZXRocjoweDQxMjNjYmQxNDNiNTVjMDZlNDUxZmYyNTNhZjA5Mjg2YjY4N2E5NTAifQ.o6eDKYjHJnak1ylkpe9g8krxvK9UEhKf-1T0EYhH8pGyb8MjOEepRJi8DYlVEnZno0DkVYXQCf3u1i_HThBKtAA" + ), + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjYWxsYmFjayI6Imh0dHBzOi8vdXBvcnQtcHJvamVjdC5naXRodWIuaW8vdXBvcnQtYW5kcm9pZC1zZGsvY2FsbGJhY2tzIiwicmVxdWVzdGVkIjpbIm5hbWUiXSwiYWN0IjoiZ2VuZXJhbCIsInR5cGUiOiJzaGFyZVJlcSIsImlhdCI6MTU1NjcyMTQxMywiZXhwIjoxNTU2NzIyMDEzLCJpc3MiOiJkaWQ6ZXRocjoweGNmMDNkZDBhODk0ZWY3OWNiNWI2MDFhNDNjNGIyNWUzYWU0YzY3ZWQifQ.KfDgkaOWZxxfprgBxPvC2wSd-BrhdjN-gTf7br5Li4LtTgSmk9I55dE2xWekSSWTaQxC74DDRCxrEsVH3I1bWwE" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val ethrDidResolver = spyk(EthrDIDResolver(JsonRPC(""))) + coEvery { ethrDidResolver.resolve(eq(issuer)) } returns + EthrDIDDocument.fromJson(""" { "@context": "https://w3id.org/did/v1", "id": "$issuer", "publicKey": [{ "id": "$issuer#owner", "type": "Secp256k1VerificationKey2018", "owner": "$issuer", "ethereumAddress": "${signer.getAddress()}"}], "authentication": [{ "type": "Secp256k1SignatureAuthentication2018", "publicKey": "$issuer#owner"}] } """) + + val uportDidResolver = spyk(UportDIDResolver(JsonRPC(""))) + coEvery { uportDidResolver.resolve(eq("2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG")) } returns + //language=json + UportDIDDocument.fromJson("""{"id":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG","publicKey":[{"id":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG#keys-1","type":"Secp256k1VerificationKey2018","owner":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG","ethereumAddress":"0x476c88ed464efd251a8b18eb84785f7c46807873"}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG#keys-1"}],"service":[],"@context":"https://w3id.org/did/v1", "uportProfile" : {"@type": "Person"}}""") + + UniversalDID.registerResolver(ethrDidResolver) + UniversalDID.registerResolver(uportDidResolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + val uPortProfile = Credentials(issuer, signer).verifyDisclosure(token) + + assertThat(uPortProfile).isNotNull() + assertThat(uPortProfile.did).isEqualTo(issuer) + assertThat(uPortProfile.networkId).isEqualTo("0x4") + assertThat(uPortProfile.name).isEqualTo("Mike Gunn") + assertThat(uPortProfile.email).isEqualTo("mgunn@uport.me") + assertThat(uPortProfile.invalid.size + uPortProfile.valid.size).isEqualTo((map["verified"] as List?)?.size) + } + + @Test + @Suppress("UNCHECKED_CAST") + fun `can fetch networkId from request token`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "aud" to "did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjYWxsYmFjayI6Imh0dHBzOi8vdXBvcnQtcHJvamVjdC5naXRodWIuaW8vdXBvcnQtYW5kcm9pZC1zZGsvY2FsbGJhY2tzIiwicmVxdWVzdGVkIjpbIm5hbWUiLCJib3hQdWIiLCJuZXQiXSwibmV0IjoiMHg0IiwiYWN0IjoiZ2VuZXJhbCIsInR5cGUiOiJzaGFyZVJlcSIsImlhdCI6MTU1NzEzNzczMCwiZXhwIjoxNTU3MTM4MzMwLCJpc3MiOiJkaWQ6ZXRocjoweGNmMDNkZDBhODk0ZWY3OWNiNWI2MDFhNDNjNGIyNWUzYWU0YzY3ZWQifQ.xPnTKcFsE3MRxkm6I__xSRVSFQgIT5tUgfL_O7q0hfPTNxnA8DM53yqMdl_1stqzoIv2VKgMC40oFfYh9Ql-TAA" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + val uPortProfile = Credentials(issuer, signer).verifyDisclosure(token) + + assertThat(uPortProfile).isNotNull() + assertThat(uPortProfile.networkId).isEqualTo("0x4") + } + + @Test + fun `can return uport profile from jwt payload without all properties`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "aud" to "did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed", + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjYWxsYmFjayI6Imh0dHBzOi8vdXBvcnQtcHJvamVjdC5naXRodWIuaW8vdXBvcnQtYW5kcm9pZC1zZGsvY2FsbGJhY2tzIiwicmVxdWVzdGVkIjpbIm5hbWUiXSwiYWN0IjoiZ2VuZXJhbCIsInR5cGUiOiJzaGFyZVJlcSIsImlhdCI6MTU1NjcyMTQxMywiZXhwIjoxNTU2NzIyMDEzLCJpc3MiOiJkaWQ6ZXRocjoweGNmMDNkZDBhODk0ZWY3OWNiNWI2MDFhNDNjNGIyNWUzYWU0YzY3ZWQifQ.KfDgkaOWZxxfprgBxPvC2wSd-BrhdjN-gTf7br5Li4LtTgSmk9I55dE2xWekSSWTaQxC74DDRCxrEsVH3I1bWwE" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + val uPortProfile = Credentials(issuer, signer).verifyDisclosure(token) + + assertThat(uPortProfile).isNotNull() + assertThat(uPortProfile.did).isEqualTo(issuer) + } + + @Test + fun `successfully authenticates selective disclosure response`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "aud" to "did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed", + "net" to "0x4", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjYWxsYmFjayI6Imh0dHBzOi8vdXBvcnQtcHJvamVjdC5naXRodWIuaW8vdXBvcnQtYW5kcm9pZC1zZGsvY2FsbGJhY2tzIiwicmVxdWVzdGVkIjpbIm5hbWUiXSwiYWN0IjoiZ2VuZXJhbCIsInR5cGUiOiJzaGFyZVJlcSIsImlhdCI6MTU1NzM5NTExOCwiZXhwIjo5MDAwMDAwMDAxNTU3Mzk1MTE4LCJpc3MiOiJkaWQ6ZXRocjoweGNmMDNkZDBhODk0ZWY3OWNiNWI2MDFhNDNjNGIyNWUzYWU0YzY3ZWQifQ.6UVkmO5vXyNtn6gy_RKz1Wjx1eWqik_124aBfcmKFr_jv6T96xxPKIda8AMxFWvaqQ0BJo6rec-S-USBBhYFcgA" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + val authenticatedPayload = Credentials(issuer, signer).authenticateDisclosure(token) + + assertThat(authenticatedPayload).isNotNull() + Unit + } + + @Test + fun `throws error when req token is missing`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "net" to "0x4", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "permissions" to listOf("notifications") + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + coAssert { + Credentials(issuer, signer).authenticateDisclosure(token) + }.thrownError { + isInstanceOf(JWTAuthenticationException::class) + } + } + + + @Test + fun `throws error when request type is not a shareReq`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "net" to "0x4", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjYWxsYmFjayI6Imh0dHBzOi8vdXBvcnQtcHJvamVjdC5naXRodWIuaW8vdXBvcnQtYW5kcm9pZC1zZGsvY2FsbGJhY2tzIiwic3ViIjoiZGlkOmV0aHI6MHgzZmYyNTExN2MwZTE3MGNhNTMwYmQ1ODkxODk5YzE4Mzk0NGRiNDMxIiwidHlwZSI6InZlclJlcSIsInVuc2lnbmVkQ2xhaW0iOnsiY2l0aXplbiBvZiBDbGV2ZXJsYW5kIjp0cnVlfSwiaWF0IjoxNTU3NDE3MTczLCJleHAiOjkwMDAwMDAwMDE1NTc0MTcxNzMsImlzcyI6ImRpZDpldGhyOjB4Y2YwM2RkMGE4OTRlZjc5Y2I1YjYwMWE0M2M0YjI1ZTNhZTRjNjdlZCJ9.hR0hmw-63WrTK-dsdzfdGhnleDY59zTIbFYk-V-L2yEoe4fn6piFBbkGeBBfVwxs7iTi679BtY8jA3pDl3OLdwA" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + coAssert { + Credentials(issuer, signer).authenticateDisclosure(token) + }.thrownError { + isInstanceOf(JWTAuthenticationException::class) + } + } + + @Test + fun `throws error when request issuer did in the request does not match issuer in the credentials`() = runBlocking { + + val map = mapOf( + "iat" to 1556541978, + "exp" to 1656628378, + "net" to "0x4", + "own" to mapOf( + "name" to "Mike Gunn", + "email" to "mgunn@uport.me" + ), + "permissions" to listOf("notifications"), + "req" to "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbXMiOnsibmFtZSI6IlIgRGFuZWVsIE9saXZhdyJ9LCJpYXQiOjE1NDgxNjM2ODgsImV4cCI6MjE3ODg4MzY4OCwiaXNzIjoiZGlkOmV0aHI6MHg0MTIzY2JkMTQzYjU1YzA2ZTQ1MWZmMjUzYWYwOTI4NmI2ODdhOTUwIn0.Tral9PIGcNIH-3LrC9sAasPokbtnny3LPw9wrEGPqARXLQREGH6l8GI9JXL3o6_qjY3KF9Nbz0wi7g-pdlC-rgA" + ) + + val signer = KPSigner("0x1234") + val issuer = "did:ethr:${signer.getAddress()}" + + val resolver = spyk(EthrDIDResolver(JsonRPC(""))) + + // Mock [EtherDIDDocument] for credentials issuer DID + coEvery { resolver.resolve(eq(issuer)) } returns EthrDIDDocument.fromJson( + """ + { + "@context": "https://w3id.org/did/v1", + "id": "$issuer", + "publicKey": [{ + "id": "$issuer#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "$issuer", + "ethereumAddress": "${signer.getAddress()}"}], + "authentication": [{ + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "$issuer#owner"}] + } + """.trimIndent() + ) + + + // Mock [EtherDIDDocument] for issuer DID in the request token embeded in the response map above + coEvery { resolver.resolve("did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950") } returns EthrDIDDocument.fromJson( + """ + { + "id": "did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950", + "publicKey": [ + { + "id": "did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950#owner", + "type": "Secp256k1VerificationKey2018", + "owner": "did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950", + "ethereumAddress": "0x4123cbd143b55c06e451ff253af09286b687a950", + "publicKeyHex": null, + "publicKeyBase64": null, + "publicKeyBase58": null, + "value": null + } + ], + "authentication": [ + { + "type": "Secp256k1SignatureAuthentication2018", + "publicKey": "did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950#owner" + } + ], + "service": [ + ], + "@context": "https://w3id.org/did/v1" + } + """.trimIndent() + ) + + UniversalDID.registerResolver(resolver) + + val token = JWTTools().createJWT(map, issuer, signer) + + coAssert { + Credentials(issuer, signer).authenticateDisclosure(token) + }.thrownError { + isInstanceOf(JWTAuthenticationException::class) + } + } +} diff --git a/demoapp/build.gradle b/demoapp/build.gradle index 659aa907..4f7491ac 100644 --- a/demoapp/build.gradle +++ b/demoapp/build.gradle @@ -45,7 +45,7 @@ dependencies { // implementation "com.github.uport-project.uport-android-sdk:sdk:$uport_sdk_version" implementation project(":sdk") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "com.android.support:appcompat-v7:$support_lib_version" implementation "com.android.support.constraint:constraint-layout:1.1.3" @@ -55,6 +55,7 @@ dependencies { androidTestImplementation "com.android.support.test.espresso:espresso-core:$espresso_version" androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espresso_version" androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espresso_version" + androidTestImplementation "com.github.mirceanis:view-matching-idler:0.1" androidTestImplementation "io.mockk:mockk-android:$mockk_version" androidTestImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" } diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/CreateAccountTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/CreateAccountTest.kt index 6cb1c4ac..adfb030d 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/CreateAccountTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/CreateAccountTest.kt @@ -2,25 +2,28 @@ package me.uport.sdk.demoapp import android.support.test.espresso.Espresso.onView import android.support.test.espresso.assertion.ViewAssertions.matches +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import android.support.test.rule.ActivityTestRule +import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.not import org.hamcrest.core.StringContains.containsString import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class CreateAccountTest { @get:Rule val activityRule = ActivityTestRule(CreateAccountActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + @Test fun accountIsCreated() { - - Thread.sleep(2000) - - onView(withId(R.id.defaultAccountView)).check(matches(withText(not(containsString("ERROR"))))) + onView(withId(R.id.defaultAccountView)) + .check(matches(withText(not(containsString("ERROR"))))) } - } \ No newline at end of file diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/NavigationTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/NavigationTest.kt index 8a3e8793..5a93d81c 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/NavigationTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/NavigationTest.kt @@ -33,53 +33,53 @@ class NavigationTest { @Test fun navigateAllActivities() { - // check if Create Account Activity is launched + // check if CreateAccountActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(0).perform(click()) intended(hasComponent(CreateAccountActivity::class.java.name)) pressBack() - // check if Create Key Activity is launched + // check if CreateKeyActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(1).perform(click()) intended(hasComponent(CreateKeyActivity::class.java.name)) pressBack() - // check if Import Key Activity is launched + // check if ImportKeyActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(2).perform(click()) intended(hasComponent(ImportKeyActivity::class.java.name)) pressBack() - // check if Key Protection Activity is launched + // check if KeyProtectionListActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(3).perform(click()) intended(hasComponent(KeyProtectionListActivity::class.java.name)) - // check if KeyGuard Protection Activity is launched + // check if KeyGuardProtectionActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(0).perform(click()) intended(hasComponent(KeyGuardProtectionActivity::class.java.name)) pressBack() - // check if FingerPrint Protection Activity is launched + // check if FingerPrintProtectionActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(1).perform(click()) intended(hasComponent(FingerPrintProtectionActivity::class.java.name)) pressBack() - // back to Main List Activity + // back to MainListActivity pressBack() - // check if Sign JWT List Activity is launched + // check if SignJWTListActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(4).perform(click()) intended(hasComponent(SignJWTListActivity::class.java.name)) - // check if Sign JWT with KeyPairSigner Activity is launched + // check if SignJWTKeyPairSignerActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(0).perform(click()) intended(hasComponent(SignJWTKeyPairSignerActivity::class.java.name)) pressBack() - // check if Sign JWT with UportHDSigner Activity is launched + // check if SignJWTUportHDSignerActivity is launched onData(anything()).inAdapterView(withId(R.id.item_list)).atPosition(1).perform(click()) intended(hasComponent(SignJWTUportHDSignerActivity::class.java.name)) pressBack() - // back to Main List Activity + // back to MainListActivity pressBack() } } \ No newline at end of file diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/PersonalSignatureTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/PersonalSignatureTest.kt index 0e1204f8..21ea6de3 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/PersonalSignatureTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/PersonalSignatureTest.kt @@ -11,21 +11,27 @@ import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.intent.Intents.intending import android.support.test.espresso.intent.matcher.IntentMatchers.hasAction import android.support.test.espresso.intent.rule.IntentsTestRule +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import me.uport.sdk.demoapp.request_flows.PersonalSignRequestActivity import me.uport.sdk.transport.RequestDispatchActivity +import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.not import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class PersonalSignatureTest { @get:Rule val intentsTestRule = IntentsTestRule(PersonalSignRequestActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + private var instrumentation: Instrumentation? = null private var monitor: Instrumentation.ActivityMonitor? = null private val filter: IntentFilter? = null @@ -59,8 +65,6 @@ class PersonalSignatureTest { // User clicks on send request. onView(withId(R.id.send_request)).perform(click()) - Thread.sleep(5000) - // Response detail TextView will no longer be empty onView(withId(R.id.response_details)).check(matches(not(withText("")))) } diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/uPortLoginTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SelectiveDisclosureFlowTest.kt similarity index 93% rename from demoapp/src/androidTest/java/me/uport/sdk/demoapp/uPortLoginTest.kt rename to demoapp/src/androidTest/java/me/uport/sdk/demoapp/SelectiveDisclosureFlowTest.kt index 73e93043..893ad97e 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/uPortLoginTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SelectiveDisclosureFlowTest.kt @@ -15,17 +15,22 @@ import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import me.uport.sdk.demoapp.request_flows.uPortLoginActivity import me.uport.sdk.transport.RequestDispatchActivity +import org.hamcrest.Matchers.allOf import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule -class uPortLoginTest { +class SelectiveDisclosureFlowTest { @get:Rule val intentsTestRule = IntentsTestRule(uPortLoginActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + private var instrumentation: Instrumentation? = null private var monitor: Instrumentation.ActivityMonitor? = null private val filter: IntentFilter? = null @@ -60,8 +65,6 @@ class uPortLoginTest { // User starts the uport login activity. onView(withId(R.id.btn_send_request)).perform(click()) - Thread.sleep(5000) - // Check if other request flow buttons visible after successful login onView(withId(R.id.btn_verified_claim)).check(matches(isDisplayed())) onView(withId(R.id.btn_personal_signature)).check(matches(isDisplayed())) diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTKeyPairTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTKeyPairTest.kt index 1bf1312e..48e4ceb9 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTKeyPairTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTKeyPairTest.kt @@ -4,7 +4,7 @@ import android.support.test.espresso.Espresso.onView import android.support.test.espresso.action.ViewActions.click import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.rule.ActivityTestRule -import assertk.assert +import assertk.assertThat import assertk.assertions.isNotNull import me.uport.sdk.demoapp.managing_jwt.SignJWTKeyPairSignerActivity import org.junit.Rule @@ -20,6 +20,6 @@ class SignJWTKeyPairTest { onView(withId(R.id.submit_btn_one)).perform(click()) - assert(activityRule.activity.signedJWT).isNotNull() + assertThat(activityRule.activity.signedJWT).isNotNull() } } \ No newline at end of file diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTUportHDTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTUportHDTest.kt index 9e271d31..78ab2c67 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTUportHDTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/SignJWTUportHDTest.kt @@ -1,7 +1,7 @@ package me.uport.sdk.demoapp import android.support.test.rule.ActivityTestRule -import assertk.assert +import assertk.assertThat import assertk.assertions.isNotEqualTo import me.uport.sdk.demoapp.managing_jwt.SignJWTUportHDSignerActivity import org.junit.Rule @@ -17,6 +17,6 @@ class SignJWTUportHDTest { Thread.sleep(1000) - assert(activityRule.activity.issuerDID).isNotEqualTo("") + assertThat(activityRule.activity.issuerDID).isNotEqualTo("") } } \ No newline at end of file diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TransactionRequestTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TransactionRequestTest.kt index 35cbc96f..f80a716d 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TransactionRequestTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TransactionRequestTest.kt @@ -11,21 +11,27 @@ import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.intent.Intents.intending import android.support.test.espresso.intent.matcher.IntentMatchers.hasAction import android.support.test.espresso.intent.rule.IntentsTestRule +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import me.uport.sdk.demoapp.request_flows.EthereumTransactionActivity import me.uport.sdk.transport.RequestDispatchActivity import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers.allOf import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class TransactionRequestTest { @get:Rule val intentsTestRule = IntentsTestRule(EthereumTransactionActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + private var instrumentation: Instrumentation? = null private var monitor: Instrumentation.ActivityMonitor? = null private val filter: IntentFilter? = null @@ -58,8 +64,6 @@ class TransactionRequestTest { // User clicks on send request. onView(withId(R.id.send_request)).perform(click()) - Thread.sleep(5000) - // Response detail TextView will no longer be empty onView(withId(R.id.response_details)).check(matches(not(withText("")))) } diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TypedDataTests.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TypedDataTests.kt index 2a1c8cc4..80694a65 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TypedDataTests.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/TypedDataTests.kt @@ -11,21 +11,27 @@ import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.intent.Intents.intending import android.support.test.espresso.intent.matcher.IntentMatchers.hasAction import android.support.test.espresso.intent.rule.IntentsTestRule +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import me.uport.sdk.demoapp.request_flows.TypedDataRequestActivity import me.uport.sdk.transport.RequestDispatchActivity import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers.allOf import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class TypedDataTests { @get:Rule val intentsTestRule = IntentsTestRule(TypedDataRequestActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + private var instrumentation: Instrumentation? = null private var monitor: Instrumentation.ActivityMonitor? = null private val filter: IntentFilter? = null @@ -59,8 +65,6 @@ class TypedDataTests { // User clicks on send request. onView(withId(R.id.send_request)).perform(click()) - Thread.sleep(5000) - // Response detail TextView will no longer be empty onView(withId(R.id.response_details)).check(matches(not(withText("")))) } diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifiedClaimTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifiedClaimTest.kt index 0705177c..ee0ccfca 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifiedClaimTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifiedClaimTest.kt @@ -11,21 +11,27 @@ import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.intent.Intents.intending import android.support.test.espresso.intent.matcher.IntentMatchers.hasAction import android.support.test.espresso.intent.rule.IntentsTestRule +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import me.uport.sdk.demoapp.request_flows.VerifiedClaimRequestActivity import me.uport.sdk.transport.RequestDispatchActivity import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers.allOf import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class VerifiedClaimTest { @get:Rule val intentsTestRule = IntentsTestRule(VerifiedClaimRequestActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + private var instrumentation: Instrumentation? = null private var monitor: Instrumentation.ActivityMonitor? = null private val filter: IntentFilter? = null @@ -59,8 +65,6 @@ class VerifiedClaimTest { // User clicks on send request. onView(withId(R.id.send_request)).perform(click()) - Thread.sleep(5000) - // Response detail textview will no longer be empty onView(withId(R.id.response_details)).check(matches(not(withText("")))) } diff --git a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifyJWTTest.kt b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifyJWTTest.kt index e30a57dc..4f4c6cae 100644 --- a/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifyJWTTest.kt +++ b/demoapp/src/androidTest/java/me/uport/sdk/demoapp/VerifyJWTTest.kt @@ -3,6 +3,7 @@ package me.uport.sdk.demoapp import android.support.test.espresso.Espresso.onView import android.support.test.espresso.action.ViewActions.click import android.support.test.espresso.assertion.ViewAssertions.matches +import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import android.support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import android.support.test.rule.ActivityTestRule @@ -15,14 +16,19 @@ import me.uport.sdk.ethrdid.EthrDIDResolver import me.uport.sdk.jsonrpc.JsonRPC import me.uport.sdk.universaldid.UniversalDID import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers.allOf import org.junit.Rule import org.junit.Test +import ro.mirceanistor.testutil.ViewMatcherIdlingRule class VerifyJWTTest { @get:Rule val activityRule = ActivityTestRule(VerifyJWTActivity::class.java) + @get:Rule + val viewMatcherIdlingRule = ViewMatcherIdlingRule(allOf(withId(R.id.progress), isDisplayed())) + @Test fun can_verify_jwt_in_activity() { @@ -60,8 +66,6 @@ class VerifyJWTTest { UniversalDID.registerResolver(ethrResolver) onView(withId(R.id.verify_btn)).perform(click()) - //XXX: for some reason the animated progressbar is not getting registered in espresso - Thread.sleep(2000) onView(withId(R.id.jwtPayload)).check(matches(not(withText("")))) } diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/CreateAccountActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/CreateAccountActivity.kt index c616a630..27f2f3ad 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/CreateAccountActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/CreateAccountActivity.kt @@ -9,7 +9,7 @@ import me.uport.sdk.Uport import me.uport.sdk.core.Networks /** - * shows a simple call to create an account and check for an existing default + * shows a simple call to create an HDAccount and checks for an existing default account */ class CreateAccountActivity : AppCompatActivity() { @@ -23,15 +23,10 @@ class CreateAccountActivity : AppCompatActivity() { val acc = runBlocking { Uport.createAccount(Networks.rinkeby.networkId) } progressBarView.visibility = View.INVISIBLE - defaultAccountView.text = "${acc.toJson(true)} \nAccount DID: ${acc.getDID()}" + - "\n" + - "Account MNID: ${acc.getMnid()}" + defaultAccountView.text = "${acc.toJson(true)} \nAccount DID: ${acc.getDID()}" } else { defaultAccountView.text = - "${Uport.defaultAccount?.toJson(true)} \nAccount DID: ${Uport.defaultAccount?.getDID()}" + - "\n" + - "MNID: ${Uport.defaultAccount?.getMnid()}" + "${Uport.defaultAccount?.toJson(true)} \nAccount DID: ${Uport.defaultAccount?.getDID()}" } - } } diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/DemoApplication.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/DemoApplication.kt index 3462522f..2a6496d7 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/DemoApplication.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/DemoApplication.kt @@ -1,6 +1,7 @@ package me.uport.sdk.demoapp import android.app.Application +import me.uport.sdk.Configuration import me.uport.sdk.Uport /** @@ -11,7 +12,7 @@ class DemoApplication : Application() { override fun onCreate() { super.onCreate() - val config = Uport.Configuration() + val config = Configuration() .setApplicationContext(this) Uport.initialize(config) diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/MainListActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/MainListActivity.kt index f995b114..ed687382 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/MainListActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/MainListActivity.kt @@ -22,7 +22,7 @@ class MainListActivity : AppCompatActivity() { private val features = arrayOf( - "Create an Account", + "Create an HDAccount", "Create a Key", "Import a Key", "Key Protection", diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTKeyPairSignerActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTKeyPairSignerActivity.kt index 0bd13249..744b38ad 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTKeyPairSignerActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTKeyPairSignerActivity.kt @@ -2,10 +2,10 @@ package me.uport.sdk.demoapp.managing_jwt import android.os.Bundle import android.support.v7.app.AppCompatActivity -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.simple_result_layout.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.UI import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTUportHDSignerActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTUportHDSignerActivity.kt index ece41c05..1525e087 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTUportHDSignerActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/managing_jwt/SignJWTUportHDSignerActivity.kt @@ -2,7 +2,6 @@ package me.uport.sdk.demoapp.managing_jwt import android.os.Bundle import android.support.v7.app.AppCompatActivity -import com.uport.sdk.signer.Signer import com.uport.sdk.signer.UportHDSigner import com.uport.sdk.signer.UportHDSignerImpl import com.uport.sdk.signer.encryption.KeyProtection @@ -10,6 +9,7 @@ import com.uport.sdk.signer.importHDSeed import kotlinx.android.synthetic.main.simple_result_layout.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import me.uport.sdk.signer.Signer import me.uport.sdk.core.UI import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools @@ -62,7 +62,7 @@ class SignJWTUportHDSignerActivity : AppCompatActivity() { GlobalScope.launch(UI) { val signedJWT: String? = try { - JWTTools().createJWT(payload, issuerDID!!, signer!!,5000) + JWTTools().createJWT(payload, issuerDID!!, signer!!, 5000) } catch (exception: Exception) { null } diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthereumTransactionActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthereumTransactionActivity.kt index 4850b948..0a42622e 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthereumTransactionActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthereumTransactionActivity.kt @@ -4,16 +4,20 @@ import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.request_flow.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.UI import me.uport.sdk.credentials.Credentials import me.uport.sdk.credentials.EthereumTransactionRequestParams import me.uport.sdk.demoapp.R -import me.uport.sdk.transport.* +import me.uport.sdk.transport.ErrorUriResponse +import me.uport.sdk.transport.HashCodeUriResponse +import me.uport.sdk.transport.ResponseParser +import me.uport.sdk.transport.Transports +import me.uport.sdk.transport.UriResponse import java.math.BigInteger /** diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthrTransactionUtils.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthrTransactionUtils.kt index 0615c06e..f671d488 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthrTransactionUtils.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/EthrTransactionUtils.kt @@ -21,7 +21,7 @@ fun getNetworkAndAddressFromDID(did: String?): Pair { if (did.isNullOrBlank()) { return ("" to "") } // converts possible ethr DIDs to a Pair of Network and Address - val ethrMatchResult = EthrDIDResolver.identityExtractPattern.find(did) + val ethrMatchResult = ethrDIDAddress().find(did) if (ethrMatchResult != null) { val (address,_) = ethrMatchResult.destructured // This demo app only uses the rinkeby network. It is not safe to assume that all `ethrDID`s are used on rinkeby @@ -37,4 +37,6 @@ fun getNetworkAndAddressFromDID(did: String?): Pair { } throw IllegalArgumentException("The provided did ($did) is not valid for this operation") -} \ No newline at end of file +} + +private fun ethrDIDAddress() = "^did:ethr:(0x[0-9a-fA-F]{40})".toRegex() \ No newline at end of file diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/PersonalSignRequestActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/PersonalSignRequestActivity.kt index 8ba6d74e..e6cc9e35 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/PersonalSignRequestActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/PersonalSignRequestActivity.kt @@ -5,18 +5,23 @@ import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.request_flow.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.Networks import me.uport.sdk.core.UI import me.uport.sdk.credentials.Credentials import me.uport.sdk.credentials.PersonalSignRequestParams import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools -import me.uport.sdk.transport.* +import me.uport.sdk.transport.ErrorUriResponse +import me.uport.sdk.transport.IntentForwardingActivity +import me.uport.sdk.transport.JWTUriResponse +import me.uport.sdk.transport.ResponseParser +import me.uport.sdk.transport.Transports +import me.uport.sdk.transport.UriResponse /** * diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/TypedDataRequestActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/TypedDataRequestActivity.kt index 735f28fe..f6b08672 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/TypedDataRequestActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/TypedDataRequestActivity.kt @@ -4,15 +4,20 @@ import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.request_flow.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.UI import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools -import me.uport.sdk.transport.* +import me.uport.sdk.transport.ErrorUriResponse +import me.uport.sdk.transport.IntentForwardingActivity +import me.uport.sdk.transport.JWTUriResponse +import me.uport.sdk.transport.ResponseParser +import me.uport.sdk.transport.Transports +import me.uport.sdk.transport.UriResponse /** * diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/VerifiedClaimRequestActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/VerifiedClaimRequestActivity.kt index 7c3f5f85..25979359 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/VerifiedClaimRequestActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/VerifiedClaimRequestActivity.kt @@ -4,17 +4,21 @@ import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.request_flow.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.UI import me.uport.sdk.credentials.Credentials import me.uport.sdk.credentials.VerifiedClaimRequestParams import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools -import me.uport.sdk.transport.* +import me.uport.sdk.transport.ErrorUriResponse +import me.uport.sdk.transport.JWTUriResponse +import me.uport.sdk.transport.ResponseParser +import me.uport.sdk.transport.Transports +import me.uport.sdk.transport.UriResponse /** * diff --git a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/uPortLoginActivity.kt b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/uPortLoginActivity.kt index 04545b65..c7f24b88 100644 --- a/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/uPortLoginActivity.kt +++ b/demoapp/src/main/java/me/uport/sdk/demoapp/request_flows/uPortLoginActivity.kt @@ -4,17 +4,21 @@ import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View -import com.uport.sdk.signer.KPSigner import kotlinx.android.synthetic.main.activity_uport_login.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import me.uport.sdk.signer.KPSigner import me.uport.sdk.core.UI import me.uport.sdk.credentials.Credentials import me.uport.sdk.credentials.SelectiveDisclosureRequestParams import me.uport.sdk.demoapp.R import me.uport.sdk.jwt.JWTTools -import me.uport.sdk.transport.* +import me.uport.sdk.transport.ErrorUriResponse +import me.uport.sdk.transport.JWTUriResponse +import me.uport.sdk.transport.ResponseParser +import me.uport.sdk.transport.Transports +import me.uport.sdk.transport.UriResponse /** * This allows the users initiate a uPort login using [SelectiveDisclosureRequest] diff --git a/ethr-did/abi/EthereumDIDRegistry.json b/ethr-did/abi/EthereumDIDRegistry.json deleted file mode 100644 index 33e87821..00000000 --- a/ethr-did/abi/EthereumDIDRegistry.json +++ /dev/null @@ -1,19907 +0,0 @@ -{ - "contractName": "EthereumDIDRegistry", - "abi": [ - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "owners", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "bytes32" - }, - { - "name": "", - "type": "address" - } - ], - "name": "delegates", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nonce", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "changed", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "identity", - "type": "address" - }, - { - "indexed": false, - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "name": "previousChange", - "type": "uint256" - } - ], - "name": "DIDOwnerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "identity", - "type": "address" - }, - { - "indexed": false, - "name": "delegateType", - "type": "bytes32" - }, - { - "indexed": false, - "name": "delegate", - "type": "address" - }, - { - "indexed": false, - "name": "validTo", - "type": "uint256" - }, - { - "indexed": false, - "name": "previousChange", - "type": "uint256" - } - ], - "name": "DIDDelegateChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "identity", - "type": "address" - }, - { - "indexed": false, - "name": "name", - "type": "bytes32" - }, - { - "indexed": false, - "name": "value", - "type": "bytes" - }, - { - "indexed": false, - "name": "validTo", - "type": "uint256" - }, - { - "indexed": false, - "name": "previousChange", - "type": "uint256" - } - ], - "name": "DIDAttributeChanged", - "type": "event" - }, - { - "constant": true, - "inputs": [ - { - "name": "identity", - "type": "address" - } - ], - "name": "identityOwner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "delegateType", - "type": "bytes32" - }, - { - "name": "delegate", - "type": "address" - } - ], - "name": "validDelegate", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "newOwner", - "type": "address" - } - ], - "name": "changeOwner", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "sigV", - "type": "uint8" - }, - { - "name": "sigR", - "type": "bytes32" - }, - { - "name": "sigS", - "type": "bytes32" - }, - { - "name": "newOwner", - "type": "address" - } - ], - "name": "changeOwnerSigned", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "delegateType", - "type": "bytes32" - }, - { - "name": "delegate", - "type": "address" - }, - { - "name": "validity", - "type": "uint256" - } - ], - "name": "addDelegate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "sigV", - "type": "uint8" - }, - { - "name": "sigR", - "type": "bytes32" - }, - { - "name": "sigS", - "type": "bytes32" - }, - { - "name": "delegateType", - "type": "bytes32" - }, - { - "name": "delegate", - "type": "address" - }, - { - "name": "validity", - "type": "uint256" - } - ], - "name": "addDelegateSigned", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "delegateType", - "type": "bytes32" - }, - { - "name": "delegate", - "type": "address" - } - ], - "name": "revokeDelegate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "sigV", - "type": "uint8" - }, - { - "name": "sigR", - "type": "bytes32" - }, - { - "name": "sigS", - "type": "bytes32" - }, - { - "name": "delegateType", - "type": "bytes32" - }, - { - "name": "delegate", - "type": "address" - } - ], - "name": "revokeDelegateSigned", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "name", - "type": "bytes32" - }, - { - "name": "value", - "type": "bytes" - }, - { - "name": "validity", - "type": "uint256" - } - ], - "name": "setAttribute", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "sigV", - "type": "uint8" - }, - { - "name": "sigR", - "type": "bytes32" - }, - { - "name": "sigS", - "type": "bytes32" - }, - { - "name": "name", - "type": "bytes32" - }, - { - "name": "value", - "type": "bytes" - }, - { - "name": "validity", - "type": "uint256" - } - ], - "name": "setAttributeSigned", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "name", - "type": "bytes32" - }, - { - "name": "value", - "type": "bytes" - } - ], - "name": "revokeAttribute", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "identity", - "type": "address" - }, - { - "name": "sigV", - "type": "uint8" - }, - { - "name": "sigR", - "type": "bytes32" - }, - { - "name": "sigS", - "type": "bytes32" - }, - { - "name": "name", - "type": "bytes32" - }, - { - "name": "value", - "type": "bytes" - } - ], - "name": "revokeAttributeSigned", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b50612273806100206000396000f3006080604052600436106100e5576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062c023da146100ea578063022914a7146101815780630d44625b14610204578063123b5e9814610289578063240cf1fa14610353578063622b2a3c146103df57806370ae92d2146104685780637ad4b0a4146104bf57806380b29f7c146105605780638733d4e8146105d157806393072684146106545780639c2c1b2b146106ee578063a7068d6614610792578063e476af5c1461080d578063f00d4b5d146108cd578063f96d0f9f14610930575b600080fd5b3480156100f657600080fd5b5061017f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610987565b005b34801561018d57600080fd5b506101c2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610998565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561021057600080fd5b50610273600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109cb565b6040518082815260200191505060405180910390f35b34801561029557600080fd5b50610351600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506109fd565b005b34801561035f57600080fd5b506103dd600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c72565b005b3480156103eb57600080fd5b5061044e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ec1565b604051808215151515815260200191505060405180910390f35b34801561047457600080fd5b506104a9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f86565b6040518082815260200191505060405180910390f35b3480156104cb57600080fd5b5061055e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610f9e565b005b34801561056c57600080fd5b506105cf600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fb1565b005b3480156105dd57600080fd5b50610612600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561066057600080fd5b506106ec600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611058565b005b3480156106fa57600080fd5b50610790600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506112b9565b005b34801561079e57600080fd5b5061080b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611524565b005b34801561081957600080fd5b506108cb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611537565b005b3480156108d957600080fd5b5061092e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a2565b005b34801561093c57600080fd5b50610971600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117b1565b6040518082815260200191505060405180910390f35b610993833384846117c9565b505050565b60006020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160205282600052604060002060205281600052604060002060205280600052604060002060009250925050505481565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548b88888860405180897effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7365744174747269627574650000000000000000000000000000000000000000815250600c01846000191660001916815260200183805190602001908083835b602083101515610c135780518252602082019150602081019050602083039250610bee565b6001836020036101000a0380198251168184511680821785525050505050509050018281526020019850505050505050505060405180910390209050610c6888610c608a8a8a8a8761196c565b868686611a90565b5050505050505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f0100000000000000000000000000000000000000000000000000000000000000023060036000610cca8b610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054898660405180877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f6368616e67654f776e6572000000000000000000000000000000000000000000815250600b018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401965050505050505060405180910390209050610eb986610eb3888888888761196c565b84611c35565b505050505050565b600080600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008560405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490504281119150509392505050565b60036020528060005260406000206000915090505481565b610fab8433858585611a90565b50505050565b610fbd83338484611e02565b505050565b6000806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1614151561104e57809150611052565b8291505b50919050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360006110b08c610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548a878760405180887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7265766f6b6544656c6567617465000000000000000000000000000000000000815250600e0183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401975050505050505050604051809103902090506112b0876112a9898989898761196c565b8585611e02565b50505050505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360006113118d610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548b88888860405180897effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f61646444656c6567617465000000000000000000000000000000000000000000815250600b0184600019166000191681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401828152602001985050505050505050506040518091039020905061151a886115128a8a8a8a8761196c565b868686612022565b5050505050505050565b6115318433858585612022565b50505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548a878760405180887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7265766f6b654174747269627574650000000000000000000000000000000000815250600f01836000191660001916815260200182805190602001908083835b60208310151561174c5780518252602082019150602081019050602083039250611727565b6001836020036101000a0380198251168184511680821785525050505050509050019750505050505050506040518091039020905061179987611792898989898761196c565b85856117c9565b50505050505050565b6117ad823383611c35565b5050565b60026020528060005260406000206000915090505481565b83836117d482610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151561180d57600080fd5b8573ffffffffffffffffffffffffffffffffffffffff167f18ab6b2ae3d64306c00ce663125f2bd680e441a098de1635bd7ad8b0d44965e485856000600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180856000191660001916815260200180602001848152602001838152602001828103825285818151815260200191508051906020019080838360005b838110156118e35780820151818401526020810190506118c8565b50505050905090810190601f1680156119105780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a243600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b600080600183878787604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156119e6573d6000803e3d6000fd5b5050506020604051035190506119fb87610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611a3457600080fd5b600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919060010191905055508091505095945050505050565b8484611a9b82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611ad457600080fd5b8673ffffffffffffffffffffffffffffffffffffffff167f18ab6b2ae3d64306c00ce663125f2bd680e441a098de1635bd7ad8b0d44965e48686864201600260008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180856000191660001916815260200180602001848152602001838152602001828103825285818151815260200191508051906020019080838360005b83811015611bab578082015181840152602081019050611b90565b50505050905090810190601f168015611bd85780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a243600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050505050505050565b8282611c4082610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611c7957600080fd5b826000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff167f38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a384600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a243600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050505050565b8383611e0d82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611e4657600080fd5b42600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008660405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508573ffffffffffffffffffffffffffffffffffffffff167f5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f7858542600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518085600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200182815260200194505050505060405180910390a243600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b848461202d82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151561206657600080fd5b824201600160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008760405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508673ffffffffffffffffffffffffffffffffffffffff167f5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f78686864201600260008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518085600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200182815260200194505050505060405180910390a243600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050505600a165627a7a72305820ce15794c08edea0fae7ce9c85210f71a312b60c8d5cb2e5fd716c2adcd7403c70029", - "deployedBytecode": "0x6080604052600436106100e5576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062c023da146100ea578063022914a7146101815780630d44625b14610204578063123b5e9814610289578063240cf1fa14610353578063622b2a3c146103df57806370ae92d2146104685780637ad4b0a4146104bf57806380b29f7c146105605780638733d4e8146105d157806393072684146106545780639c2c1b2b146106ee578063a7068d6614610792578063e476af5c1461080d578063f00d4b5d146108cd578063f96d0f9f14610930575b600080fd5b3480156100f657600080fd5b5061017f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610987565b005b34801561018d57600080fd5b506101c2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610998565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561021057600080fd5b50610273600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109cb565b6040518082815260200191505060405180910390f35b34801561029557600080fd5b50610351600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001909291905050506109fd565b005b34801561035f57600080fd5b506103dd600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c72565b005b3480156103eb57600080fd5b5061044e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ec1565b604051808215151515815260200191505060405180910390f35b34801561047457600080fd5b506104a9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f86565b6040518082815260200191505060405180910390f35b3480156104cb57600080fd5b5061055e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080359060200190929190505050610f9e565b005b34801561056c57600080fd5b506105cf600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fb1565b005b3480156105dd57600080fd5b50610612600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561066057600080fd5b506106ec600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611058565b005b3480156106fa57600080fd5b50610790600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506112b9565b005b34801561079e57600080fd5b5061080b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611524565b005b34801561081957600080fd5b506108cb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291908035600019169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611537565b005b3480156108d957600080fd5b5061092e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a2565b005b34801561093c57600080fd5b50610971600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117b1565b6040518082815260200191505060405180910390f35b610993833384846117c9565b505050565b60006020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160205282600052604060002060205281600052604060002060205280600052604060002060009250925050505481565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548b88888860405180897effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7365744174747269627574650000000000000000000000000000000000000000815250600c01846000191660001916815260200183805190602001908083835b602083101515610c135780518252602082019150602081019050602083039250610bee565b6001836020036101000a0380198251168184511680821785525050505050509050018281526020019850505050505050505060405180910390209050610c6888610c608a8a8a8a8761196c565b868686611a90565b5050505050505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f0100000000000000000000000000000000000000000000000000000000000000023060036000610cca8b610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054898660405180877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f6368616e67654f776e6572000000000000000000000000000000000000000000815250600b018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401965050505050505060405180910390209050610eb986610eb3888888888761196c565b84611c35565b505050505050565b600080600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008560405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490504281119150509392505050565b60036020528060005260406000206000915090505481565b610fab8433858585611a90565b50505050565b610fbd83338484611e02565b505050565b6000806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1614151561104e57809150611052565b8291505b50919050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360006110b08c610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548a878760405180887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7265766f6b6544656c6567617465000000000000000000000000000000000000815250600e0183600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401975050505050505050604051809103902090506112b0876112a9898989898761196c565b8585611e02565b50505050505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360006113118d610fc2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548b88888860405180897effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f61646444656c6567617465000000000000000000000000000000000000000000815250600b0184600019166000191681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401828152602001985050505050505050506040518091039020905061151a886115128a8a8a8a8761196c565b868686612022565b5050505050505050565b6115318433858585612022565b50505050565b600060197f01000000000000000000000000000000000000000000000000000000000000000260007f01000000000000000000000000000000000000000000000000000000000000000230600360008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548a878760405180887effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101877effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401807f7265766f6b654174747269627574650000000000000000000000000000000000815250600f01836000191660001916815260200182805190602001908083835b60208310151561174c5780518252602082019150602081019050602083039250611727565b6001836020036101000a0380198251168184511680821785525050505050509050019750505050505050506040518091039020905061179987611792898989898761196c565b85856117c9565b50505050505050565b6117ad823383611c35565b5050565b60026020528060005260406000206000915090505481565b83836117d482610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151561180d57600080fd5b8573ffffffffffffffffffffffffffffffffffffffff167f18ab6b2ae3d64306c00ce663125f2bd680e441a098de1635bd7ad8b0d44965e485856000600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180856000191660001916815260200180602001848152602001838152602001828103825285818151815260200191508051906020019080838360005b838110156118e35780820151818401526020810190506118c8565b50505050905090810190601f1680156119105780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a243600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b600080600183878787604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156119e6573d6000803e3d6000fd5b5050506020604051035190506119fb87610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611a3457600080fd5b600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919060010191905055508091505095945050505050565b8484611a9b82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611ad457600080fd5b8673ffffffffffffffffffffffffffffffffffffffff167f18ab6b2ae3d64306c00ce663125f2bd680e441a098de1635bd7ad8b0d44965e48686864201600260008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460405180856000191660001916815260200180602001848152602001838152602001828103825285818151815260200191508051906020019080838360005b83811015611bab578082015181840152602081019050611b90565b50505050905090810190601f168015611bd85780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a243600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050505050505050565b8282611c4082610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611c7957600080fd5b826000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff167f38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a384600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a243600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050505050565b8383611e0d82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515611e4657600080fd5b42600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008660405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508573ffffffffffffffffffffffffffffffffffffffff167f5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f7858542600260008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518085600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200182815260200194505050505060405180910390a243600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050565b848461202d82610fc2565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151561206657600080fd5b824201600160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008760405180826000191660001916815260200191505060405180910390206000191660001916815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508673ffffffffffffffffffffffffffffffffffffffff167f5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f78686864201600260008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518085600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200182815260200194505050505060405180910390a243600260008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050505050505600a165627a7a72305820ce15794c08edea0fae7ce9c85210f71a312b60c8d5cb2e5fd716c2adcd7403c70029", - "sourceMap": "25:5537:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:5537:0;;;;;;;", - "deployedSourceMap": "25:5537:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5079:138;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5079:138:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59:41;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104:81;;8:9:-1;5:2;;;30:1;27;20:12;5:2;104:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4467:364;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4467:364:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1856:326;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1856:326:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1260:217;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1260:217:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;232:37;;8:9:-1;5:2;;;30:1;27;20:12;5:2;232:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4306:157;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4306:157:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3484:160;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3484:160:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;790:189;;8:9:-1;5:2;;;30:1;27;20:12;5:2;790:189:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3648:385;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3648:385:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2736:411;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2736:411:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2553:179;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2553:179:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5220:339;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5220:339:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1734:118;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1734:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;189:39;;8:9:-1;5:2;;;30:1;27;20:12;5:2;189:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5079:138;5162:50;5178:8;5188:10;5200:4;5206:5;5162:15;:50::i;:::-;5079:138;;;:::o;59:41::-;;;;;;;;;;;;;;;;;;;;;;:::o;104:81::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;4467:364::-;4608:12;4638:4;4633:10;;4650:1;4645:7;;4654:4;4660:5;:15;4666:8;4660:15;;;;;;;;;;;;;;;;4677:8;4703:4;4709:5;4716:8;4623:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;51:19;36:153;;;182:3;176:10;171:3;164:23;98:2;93:3;89:12;82:19;;123:2;118:3;114:12;107:19;;148:2;143:3;139:12;132:19;;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;4623:102:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;4608:117;;4731:95;4744:8;4754:48;4769:8;4779:4;4785;4791;4797;4754:14;:48::i;:::-;4804:4;4810:5;4817:8;4731:12;:95::i;:::-;4467:364;;;;;;;;:::o;1856:326::-;1972:12;2002:4;1997:10;;2014:1;2009:7;;2018:4;2024:5;:30;2030:23;2044:8;2030:13;:23::i;:::-;2024:30;;;;;;;;;;;;;;;;2056:8;2081;1987:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1972:118;;2096:81;2108:8;2118:48;2133:8;2143:4;2149;2155;2161;2118:14;:48::i;:::-;2168:8;2096:11;:81::i;:::-;1856:326;;;;;;:::o;1260:217::-;1361:4;1373:13;1389:9;:19;1399:8;1389:19;;;;;;;;;;;;;;;:44;1419:12;1409:23;;;;;;;;;;;;;;;;;;;;;;;;1389:44;;;;;;;;;;;;;;;;;:54;1434:8;1389:54;;;;;;;;;;;;;;;;1373:70;;1468:3;1457:8;:14;1449:23;;1260:217;;;;;;:::o;232:37::-;;;;;;;;;;;;;;;;;:::o;4306:157::-;4401:57;4414:8;4424:10;4436:4;4442:5;4449:8;4401:12;:57::i;:::-;4306:157;;;;:::o;3484:160::-;3579:60;3594:8;3604:10;3616:12;3630:8;3579:14;:60::i;:::-;3484:160;;;:::o;790:189::-;851:7;867:13;883:6;:16;890:8;883:16;;;;;;;;;;;;;;;;;;;;;;;;;867:32;;919:3;910:5;:12;;;;906:47;;;940:5;933:12;;;;906:47;966:8;959:15;;790:189;;;;;:::o;3648:385::-;3789:12;3819:4;3814:10;;3831:1;3826:7;;3835:4;3841:5;:30;3847:23;3861:8;3847:13;:23::i;:::-;3841:30;;;;;;;;;;;;;;;;3873:8;3901:12;3915:8;3804:120;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3789:135;;3930:98;3945:8;3955:48;3970:8;3980:4;3986;3992;3998;3955:14;:48::i;:::-;4005:12;4019:8;3930:14;:98::i;:::-;3648:385;;;;;;;:::o;2736:411::-;2889:12;2919:4;2914:10;;2931:1;2926:7;;2935:4;2941:5;:30;2947:23;2961:8;2947:13;:23::i;:::-;2941:30;;;;;;;;;;;;;;;;2973:8;2998:12;3012:8;3022;2904:127;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2889:142;;3037:105;3049:8;3059:48;3074:8;3084:4;3090;3096;3102;3059:14;:48::i;:::-;3109:12;3123:8;3133;3037:11;:105::i;:::-;2736:411;;;;;;;;:::o;2553:179::-;2660:67;2672:8;2682:10;2694:12;2708:8;2718;2660:11;:67::i;:::-;2553:179;;;;:::o;5220:339::-;5349:12;5379:4;5374:10;;5391:1;5386:7;;5395:4;5401:5;:15;5407:8;5401:15;;;;;;;;;;;;;;;;5418:8;5447:4;5453:5;5364:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;51:19;36:153;;;182:3;176:10;171:3;164:23;98:2;93:3;89:12;82:19;;123:2;118:3;114:12;107:19;;148:2;143:3;139:12;132:19;;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;5364:95:0;;;;;;;;;;;;;;;;;;;;;;5349:110;;5466:88;5482:8;5492:48;5507:8;5517:4;5523;5529;5535;5492:14;:48::i;:::-;5542:4;5548:5;5466:15;:88::i;:::-;5220:339;;;;;;;:::o;1734:118::-;1804:43;1816:8;1826:10;1838:8;1804:11;:43::i;:::-;1734:118;;:::o;189:39::-;;;;;;;;;;;;;;;;;:::o;4835:240::-;4940:8;4950:5;350:23;364:8;350:13;:23::i;:::-;341:32;;:5;:32;;;332:42;;;;;;;;4988:8;4968:64;;;4998:4;5004:5;5011:1;5014:7;:17;5022:8;5014:17;;;;;;;;;;;;;;;;4968:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;4968:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5058:12;5038:7;:17;5046:8;5038:17;;;;;;;;;;;;;;;:32;;;;4835:240;;;;;;:::o;983:273::-;1096:7;1111:14;1128:33;1138:4;1144;1150;1156;1128:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1128:33:0;;;;;;;;1111:50;;1185:23;1199:8;1185:13;:23::i;:::-;1175:33;;:6;:33;;;1167:42;;;;;;;;1215:5;:15;1221:8;1215:15;;;;;;;;;;;;;;;;:17;;;;;;;;;;;;;1245:6;1238:13;;983:273;;;;;;;;:::o;4037:265::-;4154:8;4164:5;350:23;364:8;350:13;:23::i;:::-;341:32;;:5;:32;;;332:42;;;;;;;;4202:8;4182:77;;;4212:4;4218:5;4231:8;4225:3;:14;4241:7;:17;4249:8;4241:17;;;;;;;;;;;;;;;;4182:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;4182:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4285:12;4265:7;:17;4273:8;4265:17;;;;;;;;;;;;;;;:32;;;;4037:265;;;;;;;:::o;1481:249::-;1572:8;1582:5;350:23;364:8;350:13;:23::i;:::-;341:32;;:5;:32;;;332:42;;;;;;;;1614:8;1595:6;:16;1602:8;1595:16;;;;;;;;;;;;;;;;:27;;;;;;;;;;;;;;;;;;1649:8;1633:54;;;1659:8;1669:7;:17;1677:8;1669:17;;;;;;;;;;;;;;;;1633:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;1713:12;1693:7;:17;1701:8;1693:17;;;;;;;;;;;;;;;:32;;;;1481:249;;;;;:::o;3151:329::-;3267:8;3277:5;350:23;364:8;350:13;:23::i;:::-;341:32;;:5;:32;;;332:42;;;;;;;;3347:3;3290:9;:19;3300:8;3290:19;;;;;;;;;;;;;;;:44;3320:12;3310:23;;;;;;;;;;;;;;;;;;;;;;;;3290:44;;;;;;;;;;;;;;;;;:54;3335:8;3290:54;;;;;;;;;;;;;;;:60;;;;3380:8;3361:76;;;3390:12;3404:8;3414:3;3419:7;:17;3427:8;3419:17;;;;;;;;;;;;;;;;3361:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3463:12;3443:7;:17;3451:8;3443:17;;;;;;;;;;;;;;;:32;;;;3151:329;;;;;;:::o;2186:363::-;2314:8;2324:5;350:23;364:8;350:13;:23::i;:::-;341:32;;:5;:32;;;332:42;;;;;;;;2400:8;2394:3;:14;2337:9;:19;2347:8;2337:19;;;;;;;;;;;;;;;:44;2367:12;2357:23;;;;;;;;;;;;;;;;;;;;;;;;2337:44;;;;;;;;;;;;;;;;;:54;2382:8;2337:54;;;;;;;;;;;;;;;:71;;;;2438:8;2419:87;;;2448:12;2462:8;2478;2472:3;:14;2488:7;:17;2496:8;2488:17;;;;;;;;;;;;;;;;2419:87;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2532:12;2512:7;:17;2520:8;2512:17;;;;;;;;;;;;;;;:32;;;;2186:363;;;;;;;:::o", - "source": "pragma solidity ^0.4.4;\n\ncontract EthereumDIDRegistry {\n\n mapping(address => address) public owners;\n mapping(address => mapping(bytes32 => mapping(address => uint))) public delegates;\n mapping(address => uint) public changed;\n mapping(address => uint) public nonce;\n\n modifier onlyOwner(address identity, address actor) {\n require (actor == identityOwner(identity));\n _;\n }\n\n event DIDOwnerChanged(\n address indexed identity,\n address owner,\n uint previousChange\n );\n\n event DIDDelegateChanged(\n address indexed identity,\n bytes32 delegateType,\n address delegate,\n uint validTo,\n uint previousChange\n );\n\n event DIDAttributeChanged(\n address indexed identity,\n bytes32 name,\n bytes value,\n uint validTo,\n uint previousChange\n );\n\n function identityOwner(address identity) public view returns(address) {\n address owner = owners[identity];\n if (owner != 0x0) {\n return owner;\n }\n return identity;\n }\n\n function checkSignature(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 hash) internal returns(address) {\n address signer = ecrecover(hash, sigV, sigR, sigS);\n require(signer == identityOwner(identity));\n nonce[identity]++;\n return signer;\n }\n\n function validDelegate(address identity, bytes32 delegateType, address delegate) public view returns(bool) {\n uint validity = delegates[identity][keccak256(delegateType)][delegate];\n return (validity > now);\n }\n\n function changeOwner(address identity, address actor, address newOwner) internal onlyOwner(identity, actor) {\n owners[identity] = newOwner;\n emit DIDOwnerChanged(identity, newOwner, changed[identity]);\n changed[identity] = block.number;\n }\n\n function changeOwner(address identity, address newOwner) public {\n changeOwner(identity, msg.sender, newOwner);\n }\n\n function changeOwnerSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, address newOwner) public {\n bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, \"changeOwner\", newOwner);\n changeOwner(identity, checkSignature(identity, sigV, sigR, sigS, hash), newOwner);\n }\n\n function addDelegate(address identity, address actor, bytes32 delegateType, address delegate, uint validity) internal onlyOwner(identity, actor) {\n delegates[identity][keccak256(delegateType)][delegate] = now + validity;\n emit DIDDelegateChanged(identity, delegateType, delegate, now + validity, changed[identity]);\n changed[identity] = block.number;\n }\n\n function addDelegate(address identity, bytes32 delegateType, address delegate, uint validity) public {\n addDelegate(identity, msg.sender, delegateType, delegate, validity);\n }\n\n function addDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate, uint validity) public {\n bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, \"addDelegate\", delegateType, delegate, validity);\n addDelegate(identity, checkSignature(identity, sigV, sigR, sigS, hash), delegateType, delegate, validity);\n }\n\n function revokeDelegate(address identity, address actor, bytes32 delegateType, address delegate) internal onlyOwner(identity, actor) {\n delegates[identity][keccak256(delegateType)][delegate] = now;\n emit DIDDelegateChanged(identity, delegateType, delegate, now, changed[identity]);\n changed[identity] = block.number;\n }\n\n function revokeDelegate(address identity, bytes32 delegateType, address delegate) public {\n revokeDelegate(identity, msg.sender, delegateType, delegate);\n }\n\n function revokeDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate) public {\n bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, \"revokeDelegate\", delegateType, delegate);\n revokeDelegate(identity, checkSignature(identity, sigV, sigR, sigS, hash), delegateType, delegate);\n }\n\n function setAttribute(address identity, address actor, bytes32 name, bytes value, uint validity ) internal onlyOwner(identity, actor) {\n emit DIDAttributeChanged(identity, name, value, now + validity, changed[identity]);\n changed[identity] = block.number;\n }\n\n function setAttribute(address identity, bytes32 name, bytes value, uint validity) public {\n setAttribute(identity, msg.sender, name, value, validity);\n }\n\n function setAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value, uint validity) public {\n bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identity], identity, \"setAttribute\", name, value, validity);\n setAttribute(identity, checkSignature(identity, sigV, sigR, sigS, hash), name, value, validity);\n }\n\n function revokeAttribute(address identity, address actor, bytes32 name, bytes value ) internal onlyOwner(identity, actor) {\n emit DIDAttributeChanged(identity, name, value, 0, changed[identity]);\n changed[identity] = block.number;\n }\n\n function revokeAttribute(address identity, bytes32 name, bytes value) public {\n revokeAttribute(identity, msg.sender, name, value);\n }\n\n function revokeAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value) public {\n bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identity], identity, \"revokeAttribute\", name, value); \n revokeAttribute(identity, checkSignature(identity, sigV, sigR, sigS, hash), name, value);\n }\n\n}\n", - "sourcePath": "/Users/pelleb/code/consensys/ethereum-did-registry/contracts/EthereumDIDRegistry.sol", - "ast": { - "absolutePath": "/Users/pelleb/code/consensys/ethereum-did-registry/contracts/EthereumDIDRegistry.sol", - "exportedSymbols": { - "EthereumDIDRegistry": [ - 706 - ] - }, - "id": 707, - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 1, - "literals": [ - "solidity", - "^", - "0.4", - ".4" - ], - "nodeType": "PragmaDirective", - "src": "0:23:0" - }, - { - "baseContracts": [], - "contractDependencies": [], - "contractKind": "contract", - "documentation": null, - "fullyImplemented": true, - "id": 706, - "linearizedBaseContracts": [ - 706 - ], - "name": "EthereumDIDRegistry", - "nodeType": "ContractDefinition", - "nodes": [ - { - "constant": false, - "id": 5, - "name": "owners", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "59:41:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - }, - "typeName": { - "id": 4, - "keyType": { - "id": 2, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "67:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "59:27:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - }, - "valueType": { - "id": 3, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "78:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 13, - "name": "delegates", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "104:81:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - }, - "typeName": { - "id": 12, - "keyType": { - "id": 6, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "112:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "104:64:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - }, - "valueType": { - "id": 11, - "keyType": { - "id": 7, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "131:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "Mapping", - "src": "123:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - }, - "valueType": { - "id": 10, - "keyType": { - "id": 8, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "150:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "142:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 9, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "161:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 17, - "name": "changed", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "189:39:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "typeName": { - "id": 16, - "keyType": { - "id": 14, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "197:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "189:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 15, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "208:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 21, - "name": "nonce", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "232:37:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "typeName": { - "id": 20, - "keyType": { - "id": 18, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "240:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "232:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 19, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "251:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "body": { - "id": 36, - "nodeType": "Block", - "src": "326:60:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 32, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 28, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 25, - "src": "341:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "==", - "rightExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 30, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23, - "src": "364:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 29, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "350:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 31, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "350:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "341:32:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - ], - "id": 27, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 724, - 725 - ], - "referencedDeclaration": 724, - "src": "332:7:0", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", - "typeString": "function (bool) pure" - } - }, - "id": 33, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "332:42:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 34, - "nodeType": "ExpressionStatement", - "src": "332:42:0" - }, - { - "id": 35, - "nodeType": "PlaceholderStatement", - "src": "380:1:0" - } - ] - }, - "documentation": null, - "id": 37, - "name": "onlyOwner", - "nodeType": "ModifierDefinition", - "parameters": { - "id": 26, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 23, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 37, - "src": "293:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 22, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "293:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 25, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 37, - "src": "311:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 24, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "311:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "292:33:0" - }, - "src": "274:112:0", - "visibility": "internal" - }, - { - "anonymous": false, - "documentation": null, - "id": 45, - "name": "DIDOwnerChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 44, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 39, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "417:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 38, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "417:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 41, - "indexed": false, - "name": "owner", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "447:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 40, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "447:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 43, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "466:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 42, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "466:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "411:78:0" - }, - "src": "390:100:0" - }, - { - "anonymous": false, - "documentation": null, - "id": 57, - "name": "DIDDelegateChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 56, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 47, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "524:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 46, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "524:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 49, - "indexed": false, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "554:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 48, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "554:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 51, - "indexed": false, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "580:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 50, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "580:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 53, - "indexed": false, - "name": "validTo", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "602:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 52, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "602:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 55, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "620:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 54, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "620:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "518:125:0" - }, - "src": "494:150:0" - }, - { - "anonymous": false, - "documentation": null, - "id": 69, - "name": "DIDAttributeChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 68, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 59, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "679:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 58, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "679:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 61, - "indexed": false, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "709:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 60, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "709:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 63, - "indexed": false, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "727:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 62, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "727:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 65, - "indexed": false, - "name": "validTo", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "744:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 64, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "744:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 67, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "762:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 66, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "762:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "673:112:0" - }, - "src": "648:138:0" - }, - { - "body": { - "id": 91, - "nodeType": "Block", - "src": "860:119:0", - "statements": [ - { - "assignments": [ - 77 - ], - "declarations": [ - { - "constant": false, - "id": 77, - "name": "owner", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "867:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 76, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "867:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 81, - "initialValue": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 78, - "name": "owners", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 5, - "src": "883:6:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - } - }, - "id": 80, - "indexExpression": { - "argumentTypes": null, - "id": 79, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 71, - "src": "890:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "883:16:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "867:32:0" - }, - { - "condition": { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 84, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 82, - "name": "owner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 77, - "src": "910:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "!=", - "rightExpression": { - "argumentTypes": null, - "hexValue": "307830", - "id": 83, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "919:3:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0x0" - }, - "src": "910:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "falseBody": null, - "id": 88, - "nodeType": "IfStatement", - "src": "906:47:0", - "trueBody": { - "id": 87, - "nodeType": "Block", - "src": "924:29:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 85, - "name": "owner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 77, - "src": "940:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 75, - "id": 86, - "nodeType": "Return", - "src": "933:12:0" - } - ] - } - }, - { - "expression": { - "argumentTypes": null, - "id": 89, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 71, - "src": "966:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 75, - "id": 90, - "nodeType": "Return", - "src": "959:15:0" - } - ] - }, - "documentation": null, - "id": 92, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": true, - "modifiers": [], - "name": "identityOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 72, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 71, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "813:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 70, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "813:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "812:18:0" - }, - "payable": false, - "returnParameters": { - "id": 75, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 74, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "851:7:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 73, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "851:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "850:9:0" - }, - "scope": 706, - "src": "790:189:0", - "stateMutability": "view", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 131, - "nodeType": "Block", - "src": "1105:151:0", - "statements": [ - { - "assignments": [ - 108 - ], - "declarations": [ - { - "constant": false, - "id": 108, - "name": "signer", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1111:14:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 107, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1111:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 115, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 110, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 102, - "src": "1138:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 111, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 96, - "src": "1144:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 112, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 98, - "src": "1150:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 113, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 100, - "src": "1156:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 109, - "name": "ecrecover", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 713, - "src": "1128:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_ecrecover_pure$_t_bytes32_$_t_uint8_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (bytes32,uint8,bytes32,bytes32) pure returns (address)" - } - }, - "id": 114, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1128:33:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1111:50:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 121, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 117, - "name": "signer", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 108, - "src": "1175:6:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "==", - "rightExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 119, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 94, - "src": "1199:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 118, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "1185:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 120, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1185:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "1175:33:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - ], - "id": 116, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 724, - 725 - ], - "referencedDeclaration": 724, - "src": "1167:7:0", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", - "typeString": "function (bool) pure" - } - }, - "id": 122, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1167:42:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 123, - "nodeType": "ExpressionStatement", - "src": "1167:42:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 127, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "nodeType": "UnaryOperation", - "operator": "++", - "prefix": false, - "src": "1215:17:0", - "subExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 124, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "1215:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 126, - "indexExpression": { - "argumentTypes": null, - "id": 125, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 94, - "src": "1221:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1215:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 128, - "nodeType": "ExpressionStatement", - "src": "1215:17:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 129, - "name": "signer", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 108, - "src": "1245:6:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 106, - "id": 130, - "nodeType": "Return", - "src": "1238:13:0" - } - ] - }, - "documentation": null, - "id": 132, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "checkSignature", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 103, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 94, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1007:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 93, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1007:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 96, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1025:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 95, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "1025:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 98, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1037:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 97, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1037:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 100, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1051:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 99, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1051:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 102, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1065:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 101, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1065:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1006:72:0" - }, - "payable": false, - "returnParameters": { - "id": 106, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 105, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1096:7:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 104, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1096:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1095:9:0" - }, - "scope": 706, - "src": "983:273:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 160, - "nodeType": "Block", - "src": "1367:110:0", - "statements": [ - { - "assignments": [ - 144 - ], - "declarations": [ - { - "constant": false, - "id": 144, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1373:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 143, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "1373:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 154, - "initialValue": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 145, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "1389:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 147, - "indexExpression": { - "argumentTypes": null, - "id": 146, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 134, - "src": "1399:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 151, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 149, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 136, - "src": "1419:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 148, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "1409:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 150, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1409:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 153, - "indexExpression": { - "argumentTypes": null, - "id": 152, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 138, - "src": "1434:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1373:70:0" - }, - { - "expression": { - "argumentTypes": null, - "components": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 157, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 155, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 144, - "src": "1457:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": ">", - "rightExpression": { - "argumentTypes": null, - "id": 156, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "1468:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "1457:14:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "id": 158, - "isConstant": false, - "isInlineArray": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "nodeType": "TupleExpression", - "src": "1456:16:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "functionReturnParameters": 142, - "id": 159, - "nodeType": "Return", - "src": "1449:23:0" - } - ] - }, - "documentation": null, - "id": 161, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": true, - "modifiers": [], - "name": "validDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 139, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 134, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1283:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 133, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1283:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 136, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1301:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 135, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1301:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 138, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1323:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 137, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1323:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1282:58:0" - }, - "payable": false, - "returnParameters": { - "id": 142, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 141, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1361:4:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 140, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "1361:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1360:6:0" - }, - "scope": 706, - "src": "1260:217:0", - "stateMutability": "view", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 195, - "nodeType": "Block", - "src": "1589:141:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 178, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 174, - "name": "owners", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 5, - "src": "1595:6:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - } - }, - "id": 176, - "indexExpression": { - "argumentTypes": null, - "id": 175, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1602:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1595:16:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "id": 177, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 167, - "src": "1614:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "1595:27:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "id": 179, - "nodeType": "ExpressionStatement", - "src": "1595:27:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 181, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1649:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 182, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 167, - "src": "1659:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 183, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "1669:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 185, - "indexExpression": { - "argumentTypes": null, - "id": 184, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1677:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1669:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 180, - "name": "DIDOwnerChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 45, - "src": "1633:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,uint256)" - } - }, - "id": 186, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1633:54:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 187, - "nodeType": "EmitStatement", - "src": "1628:59:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 193, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 188, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "1693:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 190, - "indexExpression": { - "argumentTypes": null, - "id": 189, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1701:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1693:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 191, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "1713:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 192, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "1713:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "1693:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 194, - "nodeType": "ExpressionStatement", - "src": "1693:32:0" - } - ] - }, - "documentation": null, - "id": 196, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 170, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1572:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 171, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 165, - "src": "1582:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 172, - "modifierName": { - "argumentTypes": null, - "id": 169, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "1562:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "1562:26:0" - } - ], - "name": "changeOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 168, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 163, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1502:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 162, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1502:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 165, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1520:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 164, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1520:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 167, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1535:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 166, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1535:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1501:51:0" - }, - "payable": false, - "returnParameters": { - "id": 173, - "nodeType": "ParameterList", - "parameters": [], - "src": "1589:0:0" - }, - "scope": 706, - "src": "1481:249:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 210, - "nodeType": "Block", - "src": "1798:54:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 204, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 198, - "src": "1816:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 205, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "1826:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 206, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "1826:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 207, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 200, - "src": "1838:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 203, - "name": "changeOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 196, - 211 - ], - "referencedDeclaration": 196, - "src": "1804:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_address_$returns$__$", - "typeString": "function (address,address,address)" - } - }, - "id": 208, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1804:43:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 209, - "nodeType": "ExpressionStatement", - "src": "1804:43:0" - } - ] - }, - "documentation": null, - "id": 211, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "changeOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 201, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 198, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 211, - "src": "1755:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 197, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1755:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 200, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 211, - "src": "1773:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 199, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1773:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1754:36:0" - }, - "payable": false, - "returnParameters": { - "id": 202, - "nodeType": "ParameterList", - "parameters": [], - "src": "1798:0:0" - }, - "scope": 706, - "src": "1734:118:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 256, - "nodeType": "Block", - "src": "1966:216:0", - "statements": [ - { - "assignments": [ - 225 - ], - "declarations": [ - { - "constant": false, - "id": 225, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1972:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 224, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1972:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 243, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 228, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2002:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 227, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "1997:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 229, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1997:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 231, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2014:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 230, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2009:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 232, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2009:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 233, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "2018:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 234, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "2024:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 238, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 236, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2044:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 235, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "2030:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 237, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2030:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2024:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 239, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2056:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "6368616e67654f776e6572", - "id": 240, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2066:13:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_497a2d03cc86298e55cb693e1ab1fe854c7b50c0aa5aad6229104986e0bf69c9", - "typeString": "literal_string \"changeOwner\"" - }, - "value": "changeOwner" - }, - { - "argumentTypes": null, - "id": 241, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 221, - "src": "2081:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_497a2d03cc86298e55cb693e1ab1fe854c7b50c0aa5aad6229104986e0bf69c9", - "typeString": "literal_string \"changeOwner\"" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 226, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "1987:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 242, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1987:103:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1972:118:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 245, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2108:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 247, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2133:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 248, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 215, - "src": "2143:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 249, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 217, - "src": "2149:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 250, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 219, - "src": "2155:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 251, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 225, - "src": "2161:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 246, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "2118:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 252, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2118:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 253, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 221, - "src": "2168:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 244, - "name": "changeOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 196, - 211 - ], - "referencedDeclaration": 196, - "src": "2096:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_address_$returns$__$", - "typeString": "function (address,address,address)" - } - }, - "id": 254, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2096:81:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 255, - "nodeType": "ExpressionStatement", - "src": "2096:81:0" - } - ] - }, - "documentation": null, - "id": 257, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "changeOwnerSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 222, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 213, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1883:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 212, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1883:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 215, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1901:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 214, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "1901:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 217, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1913:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 216, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1913:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 219, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1927:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 218, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1927:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 221, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1941:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 220, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1941:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1882:76:0" - }, - "payable": false, - "returnParameters": { - "id": 223, - "nodeType": "ParameterList", - "parameters": [], - "src": "1966:0:0" - }, - "scope": 706, - "src": "1856:326:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 307, - "nodeType": "Block", - "src": "2331:218:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 286, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 274, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "2337:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 280, - "indexExpression": { - "argumentTypes": null, - "id": 275, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2347:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2337:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 281, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 277, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 263, - "src": "2367:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 276, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "2357:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 278, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2357:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2337:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 282, - "indexExpression": { - "argumentTypes": null, - "id": 279, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 265, - "src": "2382:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "2337:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 285, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 283, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "2394:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 284, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 267, - "src": "2400:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2394:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2337:71:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 287, - "nodeType": "ExpressionStatement", - "src": "2337:71:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 289, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2438:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 290, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 263, - "src": "2448:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 291, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 265, - "src": "2462:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 294, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 292, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "2472:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 293, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 267, - "src": "2478:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2472:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 295, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "2488:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 297, - "indexExpression": { - "argumentTypes": null, - "id": 296, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2496:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2488:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 288, - "name": "DIDDelegateChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 57, - "src": "2419:18:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,address,uint256,uint256)" - } - }, - "id": 298, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2419:87:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 299, - "nodeType": "EmitStatement", - "src": "2414:92:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 305, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 300, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "2512:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 302, - "indexExpression": { - "argumentTypes": null, - "id": 301, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2520:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "2512:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 303, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "2532:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 304, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "2532:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2512:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 306, - "nodeType": "ExpressionStatement", - "src": "2512:32:0" - } - ] - }, - "documentation": null, - "id": 308, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 270, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2314:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 271, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 261, - "src": "2324:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 272, - "modifierName": { - "argumentTypes": null, - "id": 269, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "2304:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "2304:26:0" - } - ], - "name": "addDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 268, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 259, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2207:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 258, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2207:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 261, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2225:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 260, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2225:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 263, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2240:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 262, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2240:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 265, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2262:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 264, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2262:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 267, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2280:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 266, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2280:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2206:88:0" - }, - "payable": false, - "returnParameters": { - "id": 273, - "nodeType": "ParameterList", - "parameters": [], - "src": "2331:0:0" - }, - "scope": 706, - "src": "2186:363:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 328, - "nodeType": "Block", - "src": "2654:78:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 320, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 310, - "src": "2672:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 321, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "2682:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 322, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "2682:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 323, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 312, - "src": "2694:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 324, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 314, - "src": "2708:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 325, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 316, - "src": "2718:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 319, - "name": "addDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 308, - 329 - ], - "referencedDeclaration": 308, - "src": "2660:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,address,uint256)" - } - }, - "id": 326, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2660:67:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 327, - "nodeType": "ExpressionStatement", - "src": "2660:67:0" - } - ] - }, - "documentation": null, - "id": 329, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "addDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 317, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 310, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2574:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 309, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2574:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 312, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2592:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 311, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2592:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 314, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2614:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 313, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2614:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 316, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2632:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 315, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2632:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2573:73:0" - }, - "payable": false, - "returnParameters": { - "id": 318, - "nodeType": "ParameterList", - "parameters": [], - "src": "2654:0:0" - }, - "scope": 706, - "src": "2553:179:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 382, - "nodeType": "Block", - "src": "2883:264:0", - "statements": [ - { - "assignments": [ - 347 - ], - "declarations": [ - { - "constant": false, - "id": 347, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2889:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 346, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2889:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 367, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 350, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2919:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 349, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2914:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 351, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2914:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 353, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2931:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 352, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2926:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 354, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2926:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 355, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "2935:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 356, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "2941:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 360, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 358, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "2961:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 357, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "2947:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 359, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2947:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2941:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 361, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "2973:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "61646444656c6567617465", - "id": 362, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2983:13:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_debebbcfc53a895bddcfa7790235910fa4c752e6acb9c798d39f50a51a8429a2", - "typeString": "literal_string \"addDelegate\"" - }, - "value": "addDelegate" - }, - { - "argumentTypes": null, - "id": 363, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 339, - "src": "2998:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 364, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 341, - "src": "3012:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 365, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 343, - "src": "3022:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_debebbcfc53a895bddcfa7790235910fa4c752e6acb9c798d39f50a51a8429a2", - "typeString": "literal_string \"addDelegate\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 348, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "2904:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 366, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2904:127:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "2889:142:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 369, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "3049:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 371, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "3074:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 372, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 333, - "src": "3084:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 373, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 335, - "src": "3090:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 374, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 337, - "src": "3096:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 375, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 347, - "src": "3102:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 370, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "3059:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 376, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3059:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 377, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 339, - "src": "3109:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 378, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 341, - "src": "3123:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 379, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 343, - "src": "3133:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 368, - "name": "addDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 308, - 329 - ], - "referencedDeclaration": 308, - "src": "3037:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,address,uint256)" - } - }, - "id": 380, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3037:105:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 381, - "nodeType": "ExpressionStatement", - "src": "3037:105:0" - } - ] - }, - "documentation": null, - "id": 383, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "addDelegateSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 344, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 331, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2763:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 330, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2763:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 333, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2781:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 332, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "2781:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 335, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2793:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 334, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2793:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 337, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2807:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 336, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2807:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 339, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2821:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 338, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2821:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 341, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2843:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 340, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2843:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 343, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2861:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 342, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2861:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2762:113:0" - }, - "payable": false, - "returnParameters": { - "id": 345, - "nodeType": "ParameterList", - "parameters": [], - "src": "2883:0:0" - }, - "scope": 706, - "src": "2736:411:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 427, - "nodeType": "Block", - "src": "3284:196:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 408, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 398, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "3290:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 404, - "indexExpression": { - "argumentTypes": null, - "id": 399, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3300:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3290:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 405, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 401, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 389, - "src": "3320:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 400, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "3310:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 402, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3310:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3290:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 406, - "indexExpression": { - "argumentTypes": null, - "id": 403, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 391, - "src": "3335:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "3290:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "id": 407, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "3347:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "3290:60:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 409, - "nodeType": "ExpressionStatement", - "src": "3290:60:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 411, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3380:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 412, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 389, - "src": "3390:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 413, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 391, - "src": "3404:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 414, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "3414:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 415, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "3419:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 417, - "indexExpression": { - "argumentTypes": null, - "id": 416, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3427:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3419:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 410, - "name": "DIDDelegateChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 57, - "src": "3361:18:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,address,uint256,uint256)" - } - }, - "id": 418, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3361:76:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 419, - "nodeType": "EmitStatement", - "src": "3356:81:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 425, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 420, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "3443:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 422, - "indexExpression": { - "argumentTypes": null, - "id": 421, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3451:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "3443:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 423, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "3463:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 424, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "3463:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "3443:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 426, - "nodeType": "ExpressionStatement", - "src": "3443:32:0" - } - ] - }, - "documentation": null, - "id": 428, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 394, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3267:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 395, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 387, - "src": "3277:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 396, - "modifierName": { - "argumentTypes": null, - "id": 393, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "3257:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "3257:26:0" - } - ], - "name": "revokeDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 392, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 385, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3175:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 384, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3175:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 387, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3193:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 386, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3193:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 389, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3208:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 388, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3208:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 391, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3230:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 390, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3230:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3174:73:0" - }, - "payable": false, - "returnParameters": { - "id": 397, - "nodeType": "ParameterList", - "parameters": [], - "src": "3284:0:0" - }, - "scope": 706, - "src": "3151:329:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 445, - "nodeType": "Block", - "src": "3573:71:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 438, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 430, - "src": "3594:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 439, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "3604:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 440, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "3604:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 441, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 432, - "src": "3616:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 442, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 434, - "src": "3630:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 437, - "name": "revokeDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 428, - 446 - ], - "referencedDeclaration": 428, - "src": "3579:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$returns$__$", - "typeString": "function (address,address,bytes32,address)" - } - }, - "id": 443, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3579:60:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 444, - "nodeType": "ExpressionStatement", - "src": "3579:60:0" - } - ] - }, - "documentation": null, - "id": 446, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 435, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 430, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3508:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 429, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3508:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 432, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3526:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 431, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3526:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 434, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3548:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 433, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3548:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3507:58:0" - }, - "payable": false, - "returnParameters": { - "id": 436, - "nodeType": "ParameterList", - "parameters": [], - "src": "3573:0:0" - }, - "scope": 706, - "src": "3484:160:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 495, - "nodeType": "Block", - "src": "3783:250:0", - "statements": [ - { - "assignments": [ - 462 - ], - "declarations": [ - { - "constant": false, - "id": 462, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3789:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 461, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3789:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 481, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 465, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3819:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 464, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "3814:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 466, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3814:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 468, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3831:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 467, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "3826:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 469, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3826:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 470, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "3835:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 471, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "3841:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 475, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 473, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3861:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 472, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "3847:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 474, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3847:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3841:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 476, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3873:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "7265766f6b6544656c6567617465", - "id": 477, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3883:16:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_f63fea8fc7bd9fe254f7933b81fa1716b5a073ddd1aa14e432aa87d81784f86c", - "typeString": "literal_string \"revokeDelegate\"" - }, - "value": "revokeDelegate" - }, - { - "argumentTypes": null, - "id": 478, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 456, - "src": "3901:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 479, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 458, - "src": "3915:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_f63fea8fc7bd9fe254f7933b81fa1716b5a073ddd1aa14e432aa87d81784f86c", - "typeString": "literal_string \"revokeDelegate\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 463, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "3804:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 480, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3804:120:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "3789:135:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 483, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3945:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 485, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3970:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 486, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 450, - "src": "3980:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 487, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 452, - "src": "3986:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 488, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 454, - "src": "3992:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 489, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 462, - "src": "3998:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 484, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "3955:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 490, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3955:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 491, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 456, - "src": "4005:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 492, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 458, - "src": "4019:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 482, - "name": "revokeDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 428, - 446 - ], - "referencedDeclaration": 428, - "src": "3930:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$returns$__$", - "typeString": "function (address,address,bytes32,address)" - } - }, - "id": 493, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3930:98:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 494, - "nodeType": "ExpressionStatement", - "src": "3930:98:0" - } - ] - }, - "documentation": null, - "id": 496, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeDelegateSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 459, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 448, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3678:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 447, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3678:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 450, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3696:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 449, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "3696:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 452, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3708:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 451, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3708:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 454, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3722:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 453, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3722:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 456, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3736:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 455, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3736:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 458, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3758:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 457, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3758:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3677:98:0" - }, - "payable": false, - "returnParameters": { - "id": 460, - "nodeType": "ParameterList", - "parameters": [], - "src": "3783:0:0" - }, - "scope": 706, - "src": "3648:385:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 532, - "nodeType": "Block", - "src": "4171:131:0", - "statements": [ - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 514, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4202:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 515, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 502, - "src": "4212:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 516, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 504, - "src": "4218:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 519, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 517, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "4225:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 518, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 506, - "src": "4231:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "4225:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 520, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "4241:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 522, - "indexExpression": { - "argumentTypes": null, - "id": 521, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4249:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "4241:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 513, - "name": "DIDAttributeChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 69, - "src": "4182:19:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,bytes memory,uint256,uint256)" - } - }, - "id": 523, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4182:77:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 524, - "nodeType": "EmitStatement", - "src": "4177:82:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 530, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 525, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "4265:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 527, - "indexExpression": { - "argumentTypes": null, - "id": 526, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4273:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "4265:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 528, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "4285:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 529, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "4285:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "4265:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 531, - "nodeType": "ExpressionStatement", - "src": "4265:32:0" - } - ] - }, - "documentation": null, - "id": 533, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 509, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4154:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 510, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 500, - "src": "4164:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 511, - "modifierName": { - "argumentTypes": null, - "id": 508, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "4144:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "4144:26:0" - } - ], - "name": "setAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 507, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 498, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4059:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 497, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4059:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 500, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4077:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 499, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4077:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 502, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4092:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 501, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4092:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 504, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4106:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 503, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4106:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 506, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4119:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 505, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4119:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4058:76:0" - }, - "payable": false, - "returnParameters": { - "id": 512, - "nodeType": "ParameterList", - "parameters": [], - "src": "4171:0:0" - }, - "scope": 706, - "src": "4037:265:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 553, - "nodeType": "Block", - "src": "4395:68:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 545, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 535, - "src": "4414:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 546, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "4424:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 547, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "4424:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 548, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 537, - "src": "4436:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 549, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 539, - "src": "4442:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 550, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 541, - "src": "4449:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 544, - "name": "setAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 533, - 554 - ], - "referencedDeclaration": 533, - "src": "4401:12:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory,uint256)" - } - }, - "id": 551, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4401:57:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 552, - "nodeType": "ExpressionStatement", - "src": "4401:57:0" - } - ] - }, - "documentation": null, - "id": 554, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "setAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 542, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 535, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4328:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 534, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4328:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 537, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4346:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 536, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4346:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 539, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4360:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 538, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4360:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 541, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4373:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 540, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4373:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4327:60:0" - }, - "payable": false, - "returnParameters": { - "id": 543, - "nodeType": "ParameterList", - "parameters": [], - "src": "4395:0:0" - }, - "scope": 706, - "src": "4306:157:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 605, - "nodeType": "Block", - "src": "4602:229:0", - "statements": [ - { - "assignments": [ - 572 - ], - "declarations": [ - { - "constant": false, - "id": 572, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4608:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 571, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4608:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 590, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 575, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4638:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 574, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "4633:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 576, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4633:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 578, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4650:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 577, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "4645:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 579, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4645:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 580, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "4654:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 581, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "4660:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 583, - "indexExpression": { - "argumentTypes": null, - "id": 582, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4666:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "4660:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 584, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4677:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "736574417474726962757465", - "id": 585, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4687:14:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_e5bbb0cf2a185ea034bc61efc4cb764352403a5c06c1da63a3fd765abbac4ea6", - "typeString": "literal_string \"setAttribute\"" - }, - "value": "setAttribute" - }, - { - "argumentTypes": null, - "id": 586, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 564, - "src": "4703:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 587, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 566, - "src": "4709:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 588, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 568, - "src": "4716:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_e5bbb0cf2a185ea034bc61efc4cb764352403a5c06c1da63a3fd765abbac4ea6", - "typeString": "literal_string \"setAttribute\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 573, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "4623:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 589, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4623:102:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "4608:117:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 592, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4744:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 594, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4769:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 595, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 558, - "src": "4779:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 596, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 560, - "src": "4785:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 597, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 562, - "src": "4791:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 598, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 572, - "src": "4797:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 593, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "4754:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 599, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4754:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 600, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 564, - "src": "4804:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 601, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 566, - "src": "4810:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 602, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 568, - "src": "4817:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 591, - "name": "setAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 533, - 554 - ], - "referencedDeclaration": 533, - "src": "4731:12:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory,uint256)" - } - }, - "id": 603, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4731:95:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 604, - "nodeType": "ExpressionStatement", - "src": "4731:95:0" - } - ] - }, - "documentation": null, - "id": 606, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "setAttributeSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 569, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 556, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4495:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 555, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4495:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 558, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4513:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 557, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "4513:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 560, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4525:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 559, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4525:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 562, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4539:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 561, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4539:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 564, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4553:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 563, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4553:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 566, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4567:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 565, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4567:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 568, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4580:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 567, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4580:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4494:100:0" - }, - "payable": false, - "returnParameters": { - "id": 570, - "nodeType": "ParameterList", - "parameters": [], - "src": "4602:0:0" - }, - "scope": 706, - "src": "4467:364:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 638, - "nodeType": "Block", - "src": "4957:118:0", - "statements": [ - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 622, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "4988:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 623, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 612, - "src": "4998:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 624, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 614, - "src": "5004:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "hexValue": "30", - "id": 625, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5011:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 626, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "5014:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 628, - "indexExpression": { - "argumentTypes": null, - "id": 627, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "5022:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "5014:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 621, - "name": "DIDAttributeChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 69, - "src": "4968:19:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,bytes memory,uint256,uint256)" - } - }, - "id": 629, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4968:64:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 630, - "nodeType": "EmitStatement", - "src": "4963:69:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 636, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 631, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "5038:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 633, - "indexExpression": { - "argumentTypes": null, - "id": 632, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "5046:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "5038:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 634, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "5058:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 635, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "5058:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "5038:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 637, - "nodeType": "ExpressionStatement", - "src": "5038:32:0" - } - ] - }, - "documentation": null, - "id": 639, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 617, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "4940:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 618, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 610, - "src": "4950:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 619, - "modifierName": { - "argumentTypes": null, - "id": 616, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "4930:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "4930:26:0" - } - ], - "name": "revokeAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 615, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 608, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4860:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 607, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4860:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 610, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4878:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 609, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4878:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 612, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4893:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 611, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4893:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 614, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4907:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 613, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4907:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4859:61:0" - }, - "payable": false, - "returnParameters": { - "id": 620, - "nodeType": "ParameterList", - "parameters": [], - "src": "4957:0:0" - }, - "scope": 706, - "src": "4835:240:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 656, - "nodeType": "Block", - "src": "5156:61:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 649, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 641, - "src": "5178:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 650, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "5188:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 651, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "5188:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 652, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 643, - "src": "5200:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 653, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 645, - "src": "5206:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 648, - "name": "revokeAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 639, - 657 - ], - "referencedDeclaration": 639, - "src": "5162:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory)" - } - }, - "id": 654, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5162:50:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 655, - "nodeType": "ExpressionStatement", - "src": "5162:50:0" - } - ] - }, - "documentation": null, - "id": 657, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 646, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 641, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5104:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 640, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "5104:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 643, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5122:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 642, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5122:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 645, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5136:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 644, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "5136:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "5103:45:0" - }, - "payable": false, - "returnParameters": { - "id": 647, - "nodeType": "ParameterList", - "parameters": [], - "src": "5156:0:0" - }, - "scope": 706, - "src": "5079:138:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 704, - "nodeType": "Block", - "src": "5343:216:0", - "statements": [ - { - "assignments": [ - 673 - ], - "declarations": [ - { - "constant": false, - "id": 673, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5349:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 672, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5349:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 690, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 676, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5379:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 675, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "5374:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 677, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5374:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 679, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5391:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 678, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "5386:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 680, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5386:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 681, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "5395:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 682, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "5401:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 684, - "indexExpression": { - "argumentTypes": null, - "id": 683, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5407:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "5401:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 685, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5418:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "7265766f6b65417474726962757465", - "id": 686, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5428:17:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_168e4cc0ad03cc4b6896d89f8a470b9997cd8bbe87ac639c5474674fa958f860", - "typeString": "literal_string \"revokeAttribute\"" - }, - "value": "revokeAttribute" - }, - { - "argumentTypes": null, - "id": 687, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 667, - "src": "5447:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 688, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 669, - "src": "5453:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_168e4cc0ad03cc4b6896d89f8a470b9997cd8bbe87ac639c5474674fa958f860", - "typeString": "literal_string \"revokeAttribute\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 674, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "5364:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 689, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5364:95:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "5349:110:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 692, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5482:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 694, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5507:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 695, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 661, - "src": "5517:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 696, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 663, - "src": "5523:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 697, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 665, - "src": "5529:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 698, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 673, - "src": "5535:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 693, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "5492:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 699, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5492:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 700, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 667, - "src": "5542:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 701, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 669, - "src": "5548:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 691, - "name": "revokeAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 639, - 657 - ], - "referencedDeclaration": 639, - "src": "5466:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory)" - } - }, - "id": 702, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5466:88:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 703, - "nodeType": "ExpressionStatement", - "src": "5466:88:0" - } - ] - }, - "documentation": null, - "id": 705, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeAttributeSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 670, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 659, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5251:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 658, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "5251:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 661, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5269:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 660, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "5269:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 663, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5281:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 662, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5281:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 665, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5295:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 664, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5295:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 667, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5309:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 666, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5309:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 669, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5323:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 668, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "5323:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "5250:85:0" - }, - "payable": false, - "returnParameters": { - "id": 671, - "nodeType": "ParameterList", - "parameters": [], - "src": "5343:0:0" - }, - "scope": 706, - "src": "5220:339:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - } - ], - "scope": 707, - "src": "25:5537:0" - } - ], - "src": "0:5563:0" - }, - "legacyAST": { - "absolutePath": "/Users/pelleb/code/consensys/ethereum-did-registry/contracts/EthereumDIDRegistry.sol", - "exportedSymbols": { - "EthereumDIDRegistry": [ - 706 - ] - }, - "id": 707, - "nodeType": "SourceUnit", - "nodes": [ - { - "id": 1, - "literals": [ - "solidity", - "^", - "0.4", - ".4" - ], - "nodeType": "PragmaDirective", - "src": "0:23:0" - }, - { - "baseContracts": [], - "contractDependencies": [], - "contractKind": "contract", - "documentation": null, - "fullyImplemented": true, - "id": 706, - "linearizedBaseContracts": [ - 706 - ], - "name": "EthereumDIDRegistry", - "nodeType": "ContractDefinition", - "nodes": [ - { - "constant": false, - "id": 5, - "name": "owners", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "59:41:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - }, - "typeName": { - "id": 4, - "keyType": { - "id": 2, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "67:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "59:27:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - }, - "valueType": { - "id": 3, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "78:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 13, - "name": "delegates", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "104:81:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - }, - "typeName": { - "id": 12, - "keyType": { - "id": 6, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "112:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "104:64:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - }, - "valueType": { - "id": 11, - "keyType": { - "id": 7, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "131:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "Mapping", - "src": "123:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - }, - "valueType": { - "id": 10, - "keyType": { - "id": 8, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "150:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "142:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 9, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "161:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 17, - "name": "changed", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "189:39:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "typeName": { - "id": 16, - "keyType": { - "id": 14, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "197:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "189:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 15, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "208:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "constant": false, - "id": 21, - "name": "nonce", - "nodeType": "VariableDeclaration", - "scope": 706, - "src": "232:37:0", - "stateVariable": true, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "typeName": { - "id": 20, - "keyType": { - "id": 18, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "240:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Mapping", - "src": "232:24:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - }, - "valueType": { - "id": 19, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "251:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - }, - "value": null, - "visibility": "public" - }, - { - "body": { - "id": 36, - "nodeType": "Block", - "src": "326:60:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 32, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 28, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 25, - "src": "341:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "==", - "rightExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 30, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 23, - "src": "364:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 29, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "350:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 31, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "350:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "341:32:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - ], - "id": 27, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 724, - 725 - ], - "referencedDeclaration": 724, - "src": "332:7:0", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", - "typeString": "function (bool) pure" - } - }, - "id": 33, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "332:42:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 34, - "nodeType": "ExpressionStatement", - "src": "332:42:0" - }, - { - "id": 35, - "nodeType": "PlaceholderStatement", - "src": "380:1:0" - } - ] - }, - "documentation": null, - "id": 37, - "name": "onlyOwner", - "nodeType": "ModifierDefinition", - "parameters": { - "id": 26, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 23, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 37, - "src": "293:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 22, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "293:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 25, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 37, - "src": "311:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 24, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "311:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "292:33:0" - }, - "src": "274:112:0", - "visibility": "internal" - }, - { - "anonymous": false, - "documentation": null, - "id": 45, - "name": "DIDOwnerChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 44, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 39, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "417:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 38, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "417:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 41, - "indexed": false, - "name": "owner", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "447:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 40, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "447:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 43, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 45, - "src": "466:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 42, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "466:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "411:78:0" - }, - "src": "390:100:0" - }, - { - "anonymous": false, - "documentation": null, - "id": 57, - "name": "DIDDelegateChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 56, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 47, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "524:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 46, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "524:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 49, - "indexed": false, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "554:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 48, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "554:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 51, - "indexed": false, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "580:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 50, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "580:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 53, - "indexed": false, - "name": "validTo", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "602:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 52, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "602:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 55, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 57, - "src": "620:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 54, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "620:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "518:125:0" - }, - "src": "494:150:0" - }, - { - "anonymous": false, - "documentation": null, - "id": 69, - "name": "DIDAttributeChanged", - "nodeType": "EventDefinition", - "parameters": { - "id": 68, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 59, - "indexed": true, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "679:24:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 58, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "679:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 61, - "indexed": false, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "709:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 60, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "709:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 63, - "indexed": false, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "727:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 62, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "727:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 65, - "indexed": false, - "name": "validTo", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "744:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 64, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "744:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 67, - "indexed": false, - "name": "previousChange", - "nodeType": "VariableDeclaration", - "scope": 69, - "src": "762:19:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 66, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "762:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "673:112:0" - }, - "src": "648:138:0" - }, - { - "body": { - "id": 91, - "nodeType": "Block", - "src": "860:119:0", - "statements": [ - { - "assignments": [ - 77 - ], - "declarations": [ - { - "constant": false, - "id": 77, - "name": "owner", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "867:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 76, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "867:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 81, - "initialValue": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 78, - "name": "owners", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 5, - "src": "883:6:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - } - }, - "id": 80, - "indexExpression": { - "argumentTypes": null, - "id": 79, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 71, - "src": "890:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "883:16:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "867:32:0" - }, - { - "condition": { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 84, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 82, - "name": "owner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 77, - "src": "910:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "!=", - "rightExpression": { - "argumentTypes": null, - "hexValue": "307830", - "id": 83, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "919:3:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0x0" - }, - "src": "910:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "falseBody": null, - "id": 88, - "nodeType": "IfStatement", - "src": "906:47:0", - "trueBody": { - "id": 87, - "nodeType": "Block", - "src": "924:29:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 85, - "name": "owner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 77, - "src": "940:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 75, - "id": 86, - "nodeType": "Return", - "src": "933:12:0" - } - ] - } - }, - { - "expression": { - "argumentTypes": null, - "id": 89, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 71, - "src": "966:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 75, - "id": 90, - "nodeType": "Return", - "src": "959:15:0" - } - ] - }, - "documentation": null, - "id": 92, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": true, - "modifiers": [], - "name": "identityOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 72, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 71, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "813:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 70, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "813:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "812:18:0" - }, - "payable": false, - "returnParameters": { - "id": 75, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 74, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 92, - "src": "851:7:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 73, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "851:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "850:9:0" - }, - "scope": 706, - "src": "790:189:0", - "stateMutability": "view", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 131, - "nodeType": "Block", - "src": "1105:151:0", - "statements": [ - { - "assignments": [ - 108 - ], - "declarations": [ - { - "constant": false, - "id": 108, - "name": "signer", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1111:14:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 107, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1111:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 115, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 110, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 102, - "src": "1138:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 111, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 96, - "src": "1144:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 112, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 98, - "src": "1150:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 113, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 100, - "src": "1156:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 109, - "name": "ecrecover", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 713, - "src": "1128:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_ecrecover_pure$_t_bytes32_$_t_uint8_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (bytes32,uint8,bytes32,bytes32) pure returns (address)" - } - }, - "id": 114, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1128:33:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1111:50:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "id": 121, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 117, - "name": "signer", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 108, - "src": "1175:6:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "BinaryOperation", - "operator": "==", - "rightExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 119, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 94, - "src": "1199:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 118, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "1185:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 120, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1185:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "1175:33:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - ], - "id": 116, - "name": "require", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 724, - 725 - ], - "referencedDeclaration": 724, - "src": "1167:7:0", - "typeDescriptions": { - "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", - "typeString": "function (bool) pure" - } - }, - "id": 122, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1167:42:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 123, - "nodeType": "ExpressionStatement", - "src": "1167:42:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 127, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "nodeType": "UnaryOperation", - "operator": "++", - "prefix": false, - "src": "1215:17:0", - "subExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 124, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "1215:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 126, - "indexExpression": { - "argumentTypes": null, - "id": 125, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 94, - "src": "1221:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1215:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 128, - "nodeType": "ExpressionStatement", - "src": "1215:17:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 129, - "name": "signer", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 108, - "src": "1245:6:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "functionReturnParameters": 106, - "id": 130, - "nodeType": "Return", - "src": "1238:13:0" - } - ] - }, - "documentation": null, - "id": 132, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "checkSignature", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 103, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 94, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1007:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 93, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1007:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 96, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1025:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 95, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "1025:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 98, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1037:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 97, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1037:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 100, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1051:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 99, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1051:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 102, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1065:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 101, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1065:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1006:72:0" - }, - "payable": false, - "returnParameters": { - "id": 106, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 105, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 132, - "src": "1096:7:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 104, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1096:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1095:9:0" - }, - "scope": 706, - "src": "983:273:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 160, - "nodeType": "Block", - "src": "1367:110:0", - "statements": [ - { - "assignments": [ - 144 - ], - "declarations": [ - { - "constant": false, - "id": 144, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1373:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 143, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "1373:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 154, - "initialValue": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 145, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "1389:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 147, - "indexExpression": { - "argumentTypes": null, - "id": 146, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 134, - "src": "1399:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 151, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 149, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 136, - "src": "1419:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 148, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "1409:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 150, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1409:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 153, - "indexExpression": { - "argumentTypes": null, - "id": 152, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 138, - "src": "1434:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1389:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1373:70:0" - }, - { - "expression": { - "argumentTypes": null, - "components": [ - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 157, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 155, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 144, - "src": "1457:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": ">", - "rightExpression": { - "argumentTypes": null, - "id": 156, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "1468:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "1457:14:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - } - ], - "id": 158, - "isConstant": false, - "isInlineArray": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "nodeType": "TupleExpression", - "src": "1456:16:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "functionReturnParameters": 142, - "id": 159, - "nodeType": "Return", - "src": "1449:23:0" - } - ] - }, - "documentation": null, - "id": 161, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": true, - "modifiers": [], - "name": "validDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 139, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 134, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1283:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 133, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1283:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 136, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1301:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 135, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1301:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 138, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1323:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 137, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1323:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1282:58:0" - }, - "payable": false, - "returnParameters": { - "id": 142, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 141, - "name": "", - "nodeType": "VariableDeclaration", - "scope": 161, - "src": "1361:4:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - }, - "typeName": { - "id": 140, - "name": "bool", - "nodeType": "ElementaryTypeName", - "src": "1361:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bool", - "typeString": "bool" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1360:6:0" - }, - "scope": 706, - "src": "1260:217:0", - "stateMutability": "view", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 195, - "nodeType": "Block", - "src": "1589:141:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 178, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 174, - "name": "owners", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 5, - "src": "1595:6:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_address_$", - "typeString": "mapping(address => address)" - } - }, - "id": 176, - "indexExpression": { - "argumentTypes": null, - "id": 175, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1602:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1595:16:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "id": 177, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 167, - "src": "1614:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "src": "1595:27:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "id": 179, - "nodeType": "ExpressionStatement", - "src": "1595:27:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 181, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1649:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 182, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 167, - "src": "1659:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 183, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "1669:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 185, - "indexExpression": { - "argumentTypes": null, - "id": 184, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1677:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "1669:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 180, - "name": "DIDOwnerChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 45, - "src": "1633:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,uint256)" - } - }, - "id": 186, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1633:54:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 187, - "nodeType": "EmitStatement", - "src": "1628:59:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 193, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 188, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "1693:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 190, - "indexExpression": { - "argumentTypes": null, - "id": 189, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1701:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "1693:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 191, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "1713:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 192, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "1713:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "1693:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 194, - "nodeType": "ExpressionStatement", - "src": "1693:32:0" - } - ] - }, - "documentation": null, - "id": 196, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 170, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 163, - "src": "1572:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 171, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 165, - "src": "1582:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 172, - "modifierName": { - "argumentTypes": null, - "id": 169, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "1562:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "1562:26:0" - } - ], - "name": "changeOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 168, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 163, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1502:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 162, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1502:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 165, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1520:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 164, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1520:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 167, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 196, - "src": "1535:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 166, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1535:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1501:51:0" - }, - "payable": false, - "returnParameters": { - "id": 173, - "nodeType": "ParameterList", - "parameters": [], - "src": "1589:0:0" - }, - "scope": 706, - "src": "1481:249:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 210, - "nodeType": "Block", - "src": "1798:54:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 204, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 198, - "src": "1816:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 205, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "1826:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 206, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "1826:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 207, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 200, - "src": "1838:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 203, - "name": "changeOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 196, - 211 - ], - "referencedDeclaration": 196, - "src": "1804:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_address_$returns$__$", - "typeString": "function (address,address,address)" - } - }, - "id": 208, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1804:43:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 209, - "nodeType": "ExpressionStatement", - "src": "1804:43:0" - } - ] - }, - "documentation": null, - "id": 211, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "changeOwner", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 201, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 198, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 211, - "src": "1755:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 197, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1755:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 200, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 211, - "src": "1773:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 199, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1773:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1754:36:0" - }, - "payable": false, - "returnParameters": { - "id": 202, - "nodeType": "ParameterList", - "parameters": [], - "src": "1798:0:0" - }, - "scope": 706, - "src": "1734:118:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 256, - "nodeType": "Block", - "src": "1966:216:0", - "statements": [ - { - "assignments": [ - 225 - ], - "declarations": [ - { - "constant": false, - "id": 225, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1972:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 224, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1972:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 243, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 228, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2002:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 227, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "1997:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 229, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1997:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 231, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2014:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 230, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2009:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 232, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2009:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 233, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "2018:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 234, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "2024:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 238, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 236, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2044:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 235, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "2030:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 237, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2030:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2024:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 239, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2056:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "6368616e67654f776e6572", - "id": 240, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2066:13:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_497a2d03cc86298e55cb693e1ab1fe854c7b50c0aa5aad6229104986e0bf69c9", - "typeString": "literal_string \"changeOwner\"" - }, - "value": "changeOwner" - }, - { - "argumentTypes": null, - "id": 241, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 221, - "src": "2081:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_497a2d03cc86298e55cb693e1ab1fe854c7b50c0aa5aad6229104986e0bf69c9", - "typeString": "literal_string \"changeOwner\"" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 226, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "1987:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 242, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "1987:103:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "1972:118:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 245, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2108:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 247, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 213, - "src": "2133:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 248, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 215, - "src": "2143:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 249, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 217, - "src": "2149:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 250, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 219, - "src": "2155:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 251, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 225, - "src": "2161:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 246, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "2118:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 252, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2118:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 253, - "name": "newOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 221, - "src": "2168:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 244, - "name": "changeOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 196, - 211 - ], - "referencedDeclaration": 196, - "src": "2096:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_address_$returns$__$", - "typeString": "function (address,address,address)" - } - }, - "id": 254, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2096:81:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 255, - "nodeType": "ExpressionStatement", - "src": "2096:81:0" - } - ] - }, - "documentation": null, - "id": 257, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "changeOwnerSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 222, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 213, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1883:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 212, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1883:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 215, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1901:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 214, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "1901:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 217, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1913:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 216, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1913:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 219, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1927:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 218, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "1927:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 221, - "name": "newOwner", - "nodeType": "VariableDeclaration", - "scope": 257, - "src": "1941:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 220, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "1941:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "1882:76:0" - }, - "payable": false, - "returnParameters": { - "id": 223, - "nodeType": "ParameterList", - "parameters": [], - "src": "1966:0:0" - }, - "scope": 706, - "src": "1856:326:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 307, - "nodeType": "Block", - "src": "2331:218:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 286, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 274, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "2337:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 280, - "indexExpression": { - "argumentTypes": null, - "id": 275, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2347:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2337:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 281, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 277, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 263, - "src": "2367:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 276, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "2357:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 278, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2357:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2337:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 282, - "indexExpression": { - "argumentTypes": null, - "id": 279, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 265, - "src": "2382:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "2337:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 285, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 283, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "2394:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 284, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 267, - "src": "2400:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2394:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2337:71:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 287, - "nodeType": "ExpressionStatement", - "src": "2337:71:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 289, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2438:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 290, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 263, - "src": "2448:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 291, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 265, - "src": "2462:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 294, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 292, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "2472:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 293, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 267, - "src": "2478:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2472:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 295, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "2488:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 297, - "indexExpression": { - "argumentTypes": null, - "id": 296, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2496:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2488:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 288, - "name": "DIDDelegateChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 57, - "src": "2419:18:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,address,uint256,uint256)" - } - }, - "id": 298, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2419:87:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 299, - "nodeType": "EmitStatement", - "src": "2414:92:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 305, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 300, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "2512:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 302, - "indexExpression": { - "argumentTypes": null, - "id": 301, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2520:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "2512:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 303, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "2532:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 304, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "2532:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "2512:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 306, - "nodeType": "ExpressionStatement", - "src": "2512:32:0" - } - ] - }, - "documentation": null, - "id": 308, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 270, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 259, - "src": "2314:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 271, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 261, - "src": "2324:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 272, - "modifierName": { - "argumentTypes": null, - "id": 269, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "2304:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "2304:26:0" - } - ], - "name": "addDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 268, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 259, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2207:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 258, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2207:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 261, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2225:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 260, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2225:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 263, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2240:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 262, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2240:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 265, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2262:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 264, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2262:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 267, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 308, - "src": "2280:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 266, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2280:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2206:88:0" - }, - "payable": false, - "returnParameters": { - "id": 273, - "nodeType": "ParameterList", - "parameters": [], - "src": "2331:0:0" - }, - "scope": 706, - "src": "2186:363:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 328, - "nodeType": "Block", - "src": "2654:78:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 320, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 310, - "src": "2672:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 321, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "2682:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 322, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "2682:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 323, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 312, - "src": "2694:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 324, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 314, - "src": "2708:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 325, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 316, - "src": "2718:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 319, - "name": "addDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 308, - 329 - ], - "referencedDeclaration": 308, - "src": "2660:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,address,uint256)" - } - }, - "id": 326, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2660:67:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 327, - "nodeType": "ExpressionStatement", - "src": "2660:67:0" - } - ] - }, - "documentation": null, - "id": 329, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "addDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 317, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 310, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2574:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 309, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2574:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 312, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2592:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 311, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2592:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 314, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2614:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 313, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2614:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 316, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 329, - "src": "2632:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 315, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2632:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2573:73:0" - }, - "payable": false, - "returnParameters": { - "id": 318, - "nodeType": "ParameterList", - "parameters": [], - "src": "2654:0:0" - }, - "scope": 706, - "src": "2553:179:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 382, - "nodeType": "Block", - "src": "2883:264:0", - "statements": [ - { - "assignments": [ - 347 - ], - "declarations": [ - { - "constant": false, - "id": 347, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2889:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 346, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2889:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 367, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 350, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2919:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 349, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2914:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 351, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2914:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 353, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2931:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 352, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "2926:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 354, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2926:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 355, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "2935:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 356, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "2941:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 360, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 358, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "2961:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 357, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "2947:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 359, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2947:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "2941:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 361, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "2973:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "61646444656c6567617465", - "id": 362, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "2983:13:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_debebbcfc53a895bddcfa7790235910fa4c752e6acb9c798d39f50a51a8429a2", - "typeString": "literal_string \"addDelegate\"" - }, - "value": "addDelegate" - }, - { - "argumentTypes": null, - "id": 363, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 339, - "src": "2998:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 364, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 341, - "src": "3012:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 365, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 343, - "src": "3022:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_debebbcfc53a895bddcfa7790235910fa4c752e6acb9c798d39f50a51a8429a2", - "typeString": "literal_string \"addDelegate\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 348, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "2904:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 366, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "2904:127:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "2889:142:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 369, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "3049:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 371, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 331, - "src": "3074:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 372, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 333, - "src": "3084:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 373, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 335, - "src": "3090:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 374, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 337, - "src": "3096:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 375, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 347, - "src": "3102:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 370, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "3059:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 376, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3059:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 377, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 339, - "src": "3109:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 378, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 341, - "src": "3123:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 379, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 343, - "src": "3133:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 368, - "name": "addDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 308, - 329 - ], - "referencedDeclaration": 308, - "src": "3037:11:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,address,uint256)" - } - }, - "id": 380, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3037:105:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 381, - "nodeType": "ExpressionStatement", - "src": "3037:105:0" - } - ] - }, - "documentation": null, - "id": 383, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "addDelegateSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 344, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 331, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2763:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 330, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2763:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 333, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2781:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 332, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "2781:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 335, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2793:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 334, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2793:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 337, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2807:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 336, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2807:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 339, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2821:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 338, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "2821:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 341, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2843:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 340, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "2843:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 343, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 383, - "src": "2861:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 342, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "2861:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "2762:113:0" - }, - "payable": false, - "returnParameters": { - "id": 345, - "nodeType": "ParameterList", - "parameters": [], - "src": "2883:0:0" - }, - "scope": 706, - "src": "2736:411:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 427, - "nodeType": "Block", - "src": "3284:196:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "id": 408, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 398, - "name": "delegates", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 13, - "src": "3290:9:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$_$", - "typeString": "mapping(address => mapping(bytes32 => mapping(address => uint256)))" - } - }, - "id": 404, - "indexExpression": { - "argumentTypes": null, - "id": 399, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3300:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3290:19:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_bytes32_$_t_mapping$_t_address_$_t_uint256_$_$", - "typeString": "mapping(bytes32 => mapping(address => uint256))" - } - }, - "id": 405, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 401, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 389, - "src": "3320:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 400, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "3310:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 402, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3310:23:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3290:44:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 406, - "indexExpression": { - "argumentTypes": null, - "id": 403, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 391, - "src": "3335:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "3290:54:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "id": 407, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "3347:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "3290:60:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 409, - "nodeType": "ExpressionStatement", - "src": "3290:60:0" - }, - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 411, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3380:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 412, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 389, - "src": "3390:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 413, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 391, - "src": "3404:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 414, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "3414:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 415, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "3419:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 417, - "indexExpression": { - "argumentTypes": null, - "id": 416, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3427:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3419:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 410, - "name": "DIDDelegateChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 57, - "src": "3361:18:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_address_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,address,uint256,uint256)" - } - }, - "id": 418, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3361:76:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 419, - "nodeType": "EmitStatement", - "src": "3356:81:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 425, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 420, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "3443:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 422, - "indexExpression": { - "argumentTypes": null, - "id": 421, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3451:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "3443:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 423, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "3463:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 424, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "3463:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "3443:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 426, - "nodeType": "ExpressionStatement", - "src": "3443:32:0" - } - ] - }, - "documentation": null, - "id": 428, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 394, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 385, - "src": "3267:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 395, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 387, - "src": "3277:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 396, - "modifierName": { - "argumentTypes": null, - "id": 393, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "3257:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "3257:26:0" - } - ], - "name": "revokeDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 392, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 385, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3175:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 384, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3175:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 387, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3193:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 386, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3193:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 389, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3208:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 388, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3208:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 391, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 428, - "src": "3230:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 390, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3230:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3174:73:0" - }, - "payable": false, - "returnParameters": { - "id": 397, - "nodeType": "ParameterList", - "parameters": [], - "src": "3284:0:0" - }, - "scope": 706, - "src": "3151:329:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 445, - "nodeType": "Block", - "src": "3573:71:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 438, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 430, - "src": "3594:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 439, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "3604:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 440, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "3604:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 441, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 432, - "src": "3616:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 442, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 434, - "src": "3630:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 437, - "name": "revokeDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 428, - 446 - ], - "referencedDeclaration": 428, - "src": "3579:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$returns$__$", - "typeString": "function (address,address,bytes32,address)" - } - }, - "id": 443, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3579:60:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 444, - "nodeType": "ExpressionStatement", - "src": "3579:60:0" - } - ] - }, - "documentation": null, - "id": 446, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeDelegate", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 435, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 430, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3508:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 429, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3508:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 432, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3526:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 431, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3526:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 434, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 446, - "src": "3548:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 433, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3548:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3507:58:0" - }, - "payable": false, - "returnParameters": { - "id": 436, - "nodeType": "ParameterList", - "parameters": [], - "src": "3573:0:0" - }, - "scope": 706, - "src": "3484:160:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 495, - "nodeType": "Block", - "src": "3783:250:0", - "statements": [ - { - "assignments": [ - 462 - ], - "declarations": [ - { - "constant": false, - "id": 462, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3789:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 461, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3789:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 481, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 465, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3819:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 464, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "3814:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 466, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3814:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 468, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3831:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 467, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "3826:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 469, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3826:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 470, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "3835:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 471, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "3841:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 475, - "indexExpression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 473, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3861:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 472, - "name": "identityOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 92, - "src": "3847:13:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_view$_t_address_$returns$_t_address_$", - "typeString": "function (address) view returns (address)" - } - }, - "id": 474, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3847:23:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "3841:30:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 476, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3873:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "7265766f6b6544656c6567617465", - "id": 477, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "3883:16:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_f63fea8fc7bd9fe254f7933b81fa1716b5a073ddd1aa14e432aa87d81784f86c", - "typeString": "literal_string \"revokeDelegate\"" - }, - "value": "revokeDelegate" - }, - { - "argumentTypes": null, - "id": 478, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 456, - "src": "3901:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 479, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 458, - "src": "3915:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_f63fea8fc7bd9fe254f7933b81fa1716b5a073ddd1aa14e432aa87d81784f86c", - "typeString": "literal_string \"revokeDelegate\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 463, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "3804:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 480, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3804:120:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "3789:135:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 483, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3945:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 485, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 448, - "src": "3970:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 486, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 450, - "src": "3980:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 487, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 452, - "src": "3986:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 488, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 454, - "src": "3992:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 489, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 462, - "src": "3998:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 484, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "3955:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 490, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3955:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 491, - "name": "delegateType", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 456, - "src": "4005:12:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 492, - "name": "delegate", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 458, - "src": "4019:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - } - ], - "id": 482, - "name": "revokeDelegate", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 428, - 446 - ], - "referencedDeclaration": 428, - "src": "3930:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_address_$returns$__$", - "typeString": "function (address,address,bytes32,address)" - } - }, - "id": 493, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "3930:98:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 494, - "nodeType": "ExpressionStatement", - "src": "3930:98:0" - } - ] - }, - "documentation": null, - "id": 496, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeDelegateSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 459, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 448, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3678:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 447, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3678:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 450, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3696:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 449, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "3696:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 452, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3708:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 451, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3708:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 454, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3722:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 453, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3722:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 456, - "name": "delegateType", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3736:20:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 455, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "3736:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 458, - "name": "delegate", - "nodeType": "VariableDeclaration", - "scope": 496, - "src": "3758:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 457, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "3758:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "3677:98:0" - }, - "payable": false, - "returnParameters": { - "id": 460, - "nodeType": "ParameterList", - "parameters": [], - "src": "3783:0:0" - }, - "scope": 706, - "src": "3648:385:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 532, - "nodeType": "Block", - "src": "4171:131:0", - "statements": [ - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 514, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4202:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 515, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 502, - "src": "4212:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 516, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 504, - "src": "4218:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "commonType": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "id": 519, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftExpression": { - "argumentTypes": null, - "id": 517, - "name": "now", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 723, - "src": "4225:3:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "BinaryOperation", - "operator": "+", - "rightExpression": { - "argumentTypes": null, - "id": 518, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 506, - "src": "4231:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "4225:14:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 520, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "4241:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 522, - "indexExpression": { - "argumentTypes": null, - "id": 521, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4249:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "4241:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 513, - "name": "DIDAttributeChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 69, - "src": "4182:19:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,bytes memory,uint256,uint256)" - } - }, - "id": 523, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4182:77:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 524, - "nodeType": "EmitStatement", - "src": "4177:82:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 530, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 525, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "4265:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 527, - "indexExpression": { - "argumentTypes": null, - "id": 526, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4273:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "4265:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 528, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "4285:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 529, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "4285:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "4265:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 531, - "nodeType": "ExpressionStatement", - "src": "4265:32:0" - } - ] - }, - "documentation": null, - "id": 533, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 509, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 498, - "src": "4154:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 510, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 500, - "src": "4164:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 511, - "modifierName": { - "argumentTypes": null, - "id": 508, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "4144:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "4144:26:0" - } - ], - "name": "setAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 507, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 498, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4059:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 497, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4059:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 500, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4077:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 499, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4077:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 502, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4092:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 501, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4092:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 504, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4106:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 503, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4106:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 506, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 533, - "src": "4119:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 505, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4119:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4058:76:0" - }, - "payable": false, - "returnParameters": { - "id": 512, - "nodeType": "ParameterList", - "parameters": [], - "src": "4171:0:0" - }, - "scope": 706, - "src": "4037:265:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 553, - "nodeType": "Block", - "src": "4395:68:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 545, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 535, - "src": "4414:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 546, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "4424:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 547, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "4424:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 548, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 537, - "src": "4436:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 549, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 539, - "src": "4442:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 550, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 541, - "src": "4449:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 544, - "name": "setAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 533, - 554 - ], - "referencedDeclaration": 533, - "src": "4401:12:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory,uint256)" - } - }, - "id": 551, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4401:57:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 552, - "nodeType": "ExpressionStatement", - "src": "4401:57:0" - } - ] - }, - "documentation": null, - "id": 554, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "setAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 542, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 535, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4328:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 534, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4328:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 537, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4346:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 536, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4346:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 539, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4360:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 538, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4360:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 541, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 554, - "src": "4373:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 540, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4373:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4327:60:0" - }, - "payable": false, - "returnParameters": { - "id": 543, - "nodeType": "ParameterList", - "parameters": [], - "src": "4395:0:0" - }, - "scope": 706, - "src": "4306:157:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 605, - "nodeType": "Block", - "src": "4602:229:0", - "statements": [ - { - "assignments": [ - 572 - ], - "declarations": [ - { - "constant": false, - "id": 572, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4608:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 571, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4608:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 590, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 575, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4638:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 574, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "4633:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 576, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4633:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 578, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4650:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 577, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "4645:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 579, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4645:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 580, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "4654:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 581, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "4660:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 583, - "indexExpression": { - "argumentTypes": null, - "id": 582, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4666:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "4660:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 584, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4677:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "736574417474726962757465", - "id": 585, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "4687:14:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_e5bbb0cf2a185ea034bc61efc4cb764352403a5c06c1da63a3fd765abbac4ea6", - "typeString": "literal_string \"setAttribute\"" - }, - "value": "setAttribute" - }, - { - "argumentTypes": null, - "id": 586, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 564, - "src": "4703:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 587, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 566, - "src": "4709:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 588, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 568, - "src": "4716:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_e5bbb0cf2a185ea034bc61efc4cb764352403a5c06c1da63a3fd765abbac4ea6", - "typeString": "literal_string \"setAttribute\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 573, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "4623:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 589, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4623:102:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "4608:117:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 592, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4744:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 594, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 556, - "src": "4769:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 595, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 558, - "src": "4779:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 596, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 560, - "src": "4785:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 597, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 562, - "src": "4791:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 598, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 572, - "src": "4797:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 593, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "4754:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 599, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4754:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 600, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 564, - "src": "4804:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 601, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 566, - "src": "4810:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "id": 602, - "name": "validity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 568, - "src": "4817:8:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 591, - "name": "setAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 533, - 554 - ], - "referencedDeclaration": 533, - "src": "4731:12:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory,uint256)" - } - }, - "id": 603, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4731:95:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 604, - "nodeType": "ExpressionStatement", - "src": "4731:95:0" - } - ] - }, - "documentation": null, - "id": 606, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "setAttributeSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 569, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 556, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4495:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 555, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4495:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 558, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4513:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 557, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "4513:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 560, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4525:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 559, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4525:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 562, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4539:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 561, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4539:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 564, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4553:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 563, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4553:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 566, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4567:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 565, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4567:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 568, - "name": "validity", - "nodeType": "VariableDeclaration", - "scope": 606, - "src": "4580:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - "typeName": { - "id": 567, - "name": "uint", - "nodeType": "ElementaryTypeName", - "src": "4580:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4494:100:0" - }, - "payable": false, - "returnParameters": { - "id": 570, - "nodeType": "ParameterList", - "parameters": [], - "src": "4602:0:0" - }, - "scope": 706, - "src": "4467:364:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 638, - "nodeType": "Block", - "src": "4957:118:0", - "statements": [ - { - "eventCall": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 622, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "4988:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 623, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 612, - "src": "4998:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 624, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 614, - "src": "5004:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - }, - { - "argumentTypes": null, - "hexValue": "30", - "id": 625, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5011:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 626, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "5014:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 628, - "indexExpression": { - "argumentTypes": null, - "id": 627, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "5022:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "5014:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - }, - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "id": 621, - "name": "DIDAttributeChanged", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 69, - "src": "4968:19:0", - "typeDescriptions": { - "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$_t_uint256_$_t_uint256_$returns$__$", - "typeString": "function (address,bytes32,bytes memory,uint256,uint256)" - } - }, - "id": 629, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "4968:64:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 630, - "nodeType": "EmitStatement", - "src": "4963:69:0" - }, - { - "expression": { - "argumentTypes": null, - "id": 636, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "leftHandSide": { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 631, - "name": "changed", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 17, - "src": "5038:7:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 633, - "indexExpression": { - "argumentTypes": null, - "id": 632, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "5046:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": true, - "nodeType": "IndexAccess", - "src": "5038:17:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "nodeType": "Assignment", - "operator": "=", - "rightHandSide": { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 634, - "name": "block", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 711, - "src": "5058:5:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_block", - "typeString": "block" - } - }, - "id": 635, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "number", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "5058:12:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "src": "5038:32:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - "id": 637, - "nodeType": "ExpressionStatement", - "src": "5038:32:0" - } - ] - }, - "documentation": null, - "id": 639, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [ - { - "arguments": [ - { - "argumentTypes": null, - "id": 617, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 608, - "src": "4940:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 618, - "name": "actor", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 610, - "src": "4950:5:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - } - ], - "id": 619, - "modifierName": { - "argumentTypes": null, - "id": 616, - "name": "onlyOwner", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 37, - "src": "4930:9:0", - "typeDescriptions": { - "typeIdentifier": "t_modifier$_t_address_$_t_address_$", - "typeString": "modifier (address,address)" - } - }, - "nodeType": "ModifierInvocation", - "src": "4930:26:0" - } - ], - "name": "revokeAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 615, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 608, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4860:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 607, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4860:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 610, - "name": "actor", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4878:13:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 609, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "4878:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 612, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4893:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 611, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "4893:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 614, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 639, - "src": "4907:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 613, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "4907:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "4859:61:0" - }, - "payable": false, - "returnParameters": { - "id": 620, - "nodeType": "ParameterList", - "parameters": [], - "src": "4957:0:0" - }, - "scope": 706, - "src": "4835:240:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "internal" - }, - { - "body": { - "id": 656, - "nodeType": "Block", - "src": "5156:61:0", - "statements": [ - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 649, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 641, - "src": "5178:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "expression": { - "argumentTypes": null, - "id": 650, - "name": "msg", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 721, - "src": "5188:3:0", - "typeDescriptions": { - "typeIdentifier": "t_magic_message", - "typeString": "msg" - } - }, - "id": 651, - "isConstant": false, - "isLValue": false, - "isPure": false, - "lValueRequested": false, - "memberName": "sender", - "nodeType": "MemberAccess", - "referencedDeclaration": null, - "src": "5188:10:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 652, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 643, - "src": "5200:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 653, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 645, - "src": "5206:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 648, - "name": "revokeAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 639, - 657 - ], - "referencedDeclaration": 639, - "src": "5162:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory)" - } - }, - "id": 654, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5162:50:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 655, - "nodeType": "ExpressionStatement", - "src": "5162:50:0" - } - ] - }, - "documentation": null, - "id": 657, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeAttribute", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 646, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 641, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5104:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 640, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "5104:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 643, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5122:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 642, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5122:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 645, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 657, - "src": "5136:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 644, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "5136:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "5103:45:0" - }, - "payable": false, - "returnParameters": { - "id": 647, - "nodeType": "ParameterList", - "parameters": [], - "src": "5156:0:0" - }, - "scope": 706, - "src": "5079:138:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - }, - { - "body": { - "id": 704, - "nodeType": "Block", - "src": "5343:216:0", - "statements": [ - { - "assignments": [ - 673 - ], - "declarations": [ - { - "constant": false, - "id": 673, - "name": "hash", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5349:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 672, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5349:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - } - ], - "id": 690, - "initialValue": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30783139", - "id": 676, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5379:4:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - }, - "value": "0x19" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_25_by_1", - "typeString": "int_const 25" - } - ], - "id": 675, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "5374:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 677, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5374:10:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "hexValue": "30", - "id": 679, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "number", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5391:1:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - }, - "value": "0" - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_rational_0_by_1", - "typeString": "int_const 0" - } - ], - "id": 678, - "isConstant": false, - "isLValue": false, - "isPure": true, - "lValueRequested": false, - "nodeType": "ElementaryTypeNameExpression", - "src": "5386:4:0", - "typeDescriptions": { - "typeIdentifier": "t_type$_t_bytes1_$", - "typeString": "type(bytes1)" - }, - "typeName": "byte" - }, - "id": 680, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "typeConversion", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5386:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - } - }, - { - "argumentTypes": null, - "id": 681, - "name": "this", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 734, - "src": "5395:4:0", - "typeDescriptions": { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - } - }, - { - "argumentTypes": null, - "baseExpression": { - "argumentTypes": null, - "id": 682, - "name": "nonce", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 21, - "src": "5401:5:0", - "typeDescriptions": { - "typeIdentifier": "t_mapping$_t_address_$_t_uint256_$", - "typeString": "mapping(address => uint256)" - } - }, - "id": 684, - "indexExpression": { - "argumentTypes": null, - "id": 683, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5407:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "isConstant": false, - "isLValue": true, - "isPure": false, - "lValueRequested": false, - "nodeType": "IndexAccess", - "src": "5401:15:0", - "typeDescriptions": { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - }, - { - "argumentTypes": null, - "id": 685, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5418:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "hexValue": "7265766f6b65417474726962757465", - "id": 686, - "isConstant": false, - "isLValue": false, - "isPure": true, - "kind": "string", - "lValueRequested": false, - "nodeType": "Literal", - "src": "5428:17:0", - "subdenomination": null, - "typeDescriptions": { - "typeIdentifier": "t_stringliteral_168e4cc0ad03cc4b6896d89f8a470b9997cd8bbe87ac639c5474674fa958f860", - "typeString": "literal_string \"revokeAttribute\"" - }, - "value": "revokeAttribute" - }, - { - "argumentTypes": null, - "id": 687, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 667, - "src": "5447:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 688, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 669, - "src": "5453:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_bytes1", - "typeString": "bytes1" - }, - { - "typeIdentifier": "t_contract$_EthereumDIDRegistry_$706", - "typeString": "contract EthereumDIDRegistry" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_stringliteral_168e4cc0ad03cc4b6896d89f8a470b9997cd8bbe87ac639c5474674fa958f860", - "typeString": "literal_string \"revokeAttribute\"" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 674, - "name": "keccak256", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 715, - "src": "5364:9:0", - "typeDescriptions": { - "typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$", - "typeString": "function () pure returns (bytes32)" - } - }, - "id": 689, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5364:95:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "nodeType": "VariableDeclarationStatement", - "src": "5349:110:0" - }, - { - "expression": { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 692, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5482:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "arguments": [ - { - "argumentTypes": null, - "id": 694, - "name": "identity", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 659, - "src": "5507:8:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 695, - "name": "sigV", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 661, - "src": "5517:4:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - { - "argumentTypes": null, - "id": 696, - "name": "sigR", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 663, - "src": "5523:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 697, - "name": "sigS", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 665, - "src": "5529:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 698, - "name": "hash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 673, - "src": "5535:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - ], - "id": 693, - "name": "checkSignature", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 132, - "src": "5492:14:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint8_$_t_bytes32_$_t_bytes32_$_t_bytes32_$returns$_t_address_$", - "typeString": "function (address,uint8,bytes32,bytes32,bytes32) returns (address)" - } - }, - "id": 699, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5492:48:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - { - "argumentTypes": null, - "id": 700, - "name": "name", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 667, - "src": "5542:4:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - { - "argumentTypes": null, - "id": 701, - "name": "value", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": 669, - "src": "5548:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - } - ], - "expression": { - "argumentTypes": [ - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_address", - "typeString": "address" - }, - { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes memory" - } - ], - "id": 691, - "name": "revokeAttribute", - "nodeType": "Identifier", - "overloadedDeclarations": [ - 639, - 657 - ], - "referencedDeclaration": 639, - "src": "5466:15:0", - "typeDescriptions": { - "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_address_$_t_bytes32_$_t_bytes_memory_ptr_$returns$__$", - "typeString": "function (address,address,bytes32,bytes memory)" - } - }, - "id": 702, - "isConstant": false, - "isLValue": false, - "isPure": false, - "kind": "functionCall", - "lValueRequested": false, - "names": [], - "nodeType": "FunctionCall", - "src": "5466:88:0", - "typeDescriptions": { - "typeIdentifier": "t_tuple$__$", - "typeString": "tuple()" - } - }, - "id": 703, - "nodeType": "ExpressionStatement", - "src": "5466:88:0" - } - ] - }, - "documentation": null, - "id": 705, - "implemented": true, - "isConstructor": false, - "isDeclaredConst": false, - "modifiers": [], - "name": "revokeAttributeSigned", - "nodeType": "FunctionDefinition", - "parameters": { - "id": 670, - "nodeType": "ParameterList", - "parameters": [ - { - "constant": false, - "id": 659, - "name": "identity", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5251:16:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - }, - "typeName": { - "id": 658, - "name": "address", - "nodeType": "ElementaryTypeName", - "src": "5251:7:0", - "typeDescriptions": { - "typeIdentifier": "t_address", - "typeString": "address" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 661, - "name": "sigV", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5269:10:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - }, - "typeName": { - "id": 660, - "name": "uint8", - "nodeType": "ElementaryTypeName", - "src": "5269:5:0", - "typeDescriptions": { - "typeIdentifier": "t_uint8", - "typeString": "uint8" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 663, - "name": "sigR", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5281:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 662, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5281:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 665, - "name": "sigS", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5295:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 664, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5295:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 667, - "name": "name", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5309:12:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - }, - "typeName": { - "id": 666, - "name": "bytes32", - "nodeType": "ElementaryTypeName", - "src": "5309:7:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes32", - "typeString": "bytes32" - } - }, - "value": null, - "visibility": "internal" - }, - { - "constant": false, - "id": 669, - "name": "value", - "nodeType": "VariableDeclaration", - "scope": 705, - "src": "5323:11:0", - "stateVariable": false, - "storageLocation": "default", - "typeDescriptions": { - "typeIdentifier": "t_bytes_memory_ptr", - "typeString": "bytes" - }, - "typeName": { - "id": 668, - "name": "bytes", - "nodeType": "ElementaryTypeName", - "src": "5323:5:0", - "typeDescriptions": { - "typeIdentifier": "t_bytes_storage_ptr", - "typeString": "bytes" - } - }, - "value": null, - "visibility": "internal" - } - ], - "src": "5250:85:0" - }, - "payable": false, - "returnParameters": { - "id": 671, - "nodeType": "ParameterList", - "parameters": [], - "src": "5343:0:0" - }, - "scope": 706, - "src": "5220:339:0", - "stateMutability": "nonpayable", - "superFunction": null, - "visibility": "public" - } - ], - "scope": 707, - "src": "25:5537:0" - } - ], - "src": "0:5563:0" - }, - "compiler": { - "name": "solc", - "version": "0.4.24+commit.e67f0147.Emscripten.clang" - }, - "networks": { - "1": { - "events": {}, - "links": {}, - "address": "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - }, - "3": { - "events": {}, - "links": {}, - "address": "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - }, - "4": { - "events": {}, - "links": {}, - "address": "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - }, - "42": { - "events": {}, - "links": {}, - "address": "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - } - }, - "schemaVersion": "2.0.0", - "updatedAt": "2018-06-15T00:50:05.725Z" -} \ No newline at end of file diff --git a/ethr-did/build.gradle b/ethr-did/build.gradle deleted file mode 100644 index aabef048..00000000 --- a/ethr-did/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -apply plugin: "com.android.library" -apply plugin: "kotlin-android" -apply plugin: "kotlinx-serialization" -apply plugin: "bivrost" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "DID resolver for the ethr-did (ERC 1056) lightweight identity standard" - -android { - compileSdkVersion compile_sdk_version - buildToolsVersion build_tools_version - - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - multiDexEnabled true - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - dexOptions { - jumboMode true - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "com.android.support:support-annotations:$support_lib_version" - - implementation "com.github.gnosis.bivrost-kotlin:bivrost-solidity-types:$bivrost_version" - - api "com.github.walleth.kethereum:extensions:$kethereum_version" - api "com.github.walleth.kethereum:model:$kethereum_version" - api "com.github.walleth.kethereum:base58:$kethereum_version" - api project(":jsonrpc") - api project(":core") - api project(":signer") - api project(":serialization") - api project(":universal-did") - - testImplementation "junit:junit:$junit_version" - testImplementation "io.mockk:mockk:$mockk_version" - testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" -} \ No newline at end of file diff --git a/ethr-did/src/main/AndroidManifest.xml b/ethr-did/src/main/AndroidManifest.xml deleted file mode 100644 index ebcd6a15..00000000 --- a/ethr-did/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDID.kt b/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDID.kt deleted file mode 100644 index 30c59513..00000000 --- a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDID.kt +++ /dev/null @@ -1,110 +0,0 @@ -@file:Suppress("UndocumentedPublicFunction", "UndocumentedPublicClass") - -package me.uport.sdk.ethrdid - -import com.uport.sdk.signer.Signer -import com.uport.sdk.signer.signRawTx -import me.uport.sdk.jsonrpc.JsonRPC -import me.uport.sdk.universaldid.PublicKeyType -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.model.Address -import org.kethereum.model.createTransactionWithDefaults -import org.walleth.khex.hexToByteArray -import org.walleth.khex.prepend0xPrefix -import org.walleth.khex.toHexString -import pm.gnosis.model.Solidity -import java.math.BigInteger - -/** - * Enables interaction with the EthrDID registry contract - */ -class EthrDID( - private val address: String, - private val rpc: JsonRPC, - private val registry: String, - val signer: Signer -) { - - private val owner: String? = null - - - class DelegateOptions( - val delegateType: PublicKeyType = PublicKeyType.Secp256k1VerificationKey2018, - val expiresIn: Long = 86400L - ) - - suspend fun lookupOwner(cache: Boolean = true): String { - if (cache && this.owner != null) return this.owner - val encodedCall = EthereumDIDRegistry.IdentityOwner.encode(Solidity.Address(address.hexToBigInteger())) - val rawResult = rpc.ethCall(registry, encodedCall) - return rawResult.substring(rawResult.length - 40).prepend0xPrefix() - } - - suspend fun changeOwner(newOwner: String): String { - val owner = lookupOwner() - - val encodedCall = EthereumDIDRegistry.ChangeOwner.encode( - Solidity.Address(address.hexToBigInteger()), - Solidity.Address(newOwner.hexToBigInteger()) - ) - - return signAndSendContractCall(owner, encodedCall) - } - - - suspend fun addDelegate(delegate: String, options: DelegateOptions = DelegateOptions()): String { - val owner = lookupOwner() - - val encodedCall = EthereumDIDRegistry.AddDelegate.encode( - Solidity.Address(this.address.hexToBigInteger()), - Solidity.Bytes32(options.delegateType.name.toByteArray()), - Solidity.Address(delegate.hexToBigInteger()), - Solidity.UInt256(BigInteger.valueOf(options.expiresIn)) - ) - - return signAndSendContractCall(owner, encodedCall) - } - - suspend fun revokeDelegate(delegate: String, delegateType: PublicKeyType = PublicKeyType.Secp256k1VerificationKey2018): String { - val owner = this.lookupOwner() - val encodedCall = EthereumDIDRegistry.RevokeDelegate.encode( - Solidity.Address(this.address.hexToBigInteger()), - Solidity.Bytes32(delegateType.name.toByteArray()), - Solidity.Address(delegate.hexToBigInteger()) - ) - - return signAndSendContractCall(owner, encodedCall) - } - - suspend fun setAttribute(key: String, value: String, expiresIn: Long = 86400L): String { - val owner = this.lookupOwner() - val encodedCall = EthereumDIDRegistry.SetAttribute.encode( - Solidity.Address(this.address.hexToBigInteger()), - Solidity.Bytes32(key.toByteArray()), - Solidity.Bytes(value.toByteArray()), - Solidity.UInt256(BigInteger.valueOf(expiresIn)) - ) - return signAndSendContractCall(owner, encodedCall) - } - - private suspend fun signAndSendContractCall(owner: String, encodedCall: String): String { - //these requests can be done in parallel - val nonce = rpc.getTransactionCount(owner) - val networkPrice = rpc.getGasPrice() - - val unsignedTx = createTransactionWithDefaults( - from = Address(owner), - to = Address(registry), - gasLimit = BigInteger.valueOf(70_000), - //FIXME: allow overriding the gas price - gasPrice = networkPrice, - nonce = nonce, - input = encodedCall.hexToByteArray().toList(), - value = BigInteger.ZERO - ) - - val signedEncodedTx = signer.signRawTx(unsignedTx) - - return rpc.sendRawTransaction(signedEncodedTx.toHexString()) - } -} \ No newline at end of file diff --git a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDDocument.kt b/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDDocument.kt deleted file mode 100644 index 2552383e..00000000 --- a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDDocument.kt +++ /dev/null @@ -1,54 +0,0 @@ -package me.uport.sdk.ethrdid - -import kotlinx.serialization.Optional -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import me.uport.sdk.universaldid.AuthenticationEntry -import me.uport.sdk.universaldid.DIDDocument -import me.uport.sdk.universaldid.PublicKeyEntry -import me.uport.sdk.universaldid.ServiceEntry - -/** - * Encapsulates the DID document corresponding to a particular ethr-did - */ -@Serializable -data class EthrDIDDocument( - @SerialName("id") - override val id: String, - - @SerialName("publicKey") - override val publicKey: List = emptyList(), - - @SerialName("authentication") - override val authentication: List = emptyList(), - - @Optional - @SerialName("service") - override val service: List = emptyList(), - - @SerialName("@context") - override val context: String = "https://w3id.org/did/v1" -) : DIDDocument { - - override fun toString(): String = Json.indented.stringify(EthrDIDDocument.serializer(), this) - - /** - * serialize this [EthrDIDDocument] to a JSON string - */ - fun toJson() = Json.stringify(EthrDIDDocument.serializer(), this) - - companion object { - /** - * represents the null state of an [EthrDIDDocument] - */ - val blank = EthrDIDDocument("") - - /** - * Parse a json serialized [EthrDIDDocument] into an object - */ - fun fromJson(json: String) = Json.nonstrict.parse(EthrDIDDocument.serializer(), json) - } -} - - diff --git a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDResolver.kt b/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDResolver.kt deleted file mode 100644 index a40120dc..00000000 --- a/ethr-did/src/main/java/me/uport/sdk/ethrdid/EthrDIDResolver.kt +++ /dev/null @@ -1,313 +0,0 @@ -@file:Suppress("LongMethod", "ComplexMethod") - -package me.uport.sdk.ethrdid - -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PRIVATE -import com.uport.sdk.signer.Signer -import me.uport.sdk.core.ITimeProvider -import me.uport.sdk.core.SystemTimeProvider -import me.uport.sdk.core.bytes32ToString -import me.uport.sdk.core.hexToBytes32 -import me.uport.sdk.core.toBase64 -import me.uport.sdk.core.utf8 -import me.uport.sdk.ethrdid.EthereumDIDRegistry.Events.DIDAttributeChanged -import me.uport.sdk.ethrdid.EthereumDIDRegistry.Events.DIDDelegateChanged -import me.uport.sdk.jsonrpc.JsonRPC -import me.uport.sdk.jsonrpc.JsonRpcException -import me.uport.sdk.universaldid.AuthenticationEntry -import me.uport.sdk.universaldid.DIDResolver -import me.uport.sdk.universaldid.DidResolverError -import me.uport.sdk.universaldid.PublicKeyEntry -import me.uport.sdk.universaldid.PublicKeyType -import me.uport.sdk.universaldid.PublicKeyType.Companion.Secp256k1SignatureAuthentication2018 -import me.uport.sdk.universaldid.PublicKeyType.Companion.Secp256k1VerificationKey2018 -import me.uport.sdk.universaldid.ServiceEntry -import org.kethereum.encodings.encodeToBase58String -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.extensions.toHexStringNoPrefix -import org.walleth.khex.hexToByteArray -import org.walleth.khex.prepend0xPrefix -import org.walleth.khex.toHexString -import pm.gnosis.model.Solidity -import java.math.BigInteger -import java.util.* - -/** - * This is a DID resolver implementation that supports the "ethr" DID method. - * It accepts ethr-dids or simple ethereum addresses and produces a document described at: - * https://w3c-ccg.github.io/did-spec/#did-documents - * - * Example ethr did: "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a" - */ -open class EthrDIDResolver( - private val rpc: JsonRPC, - //TODO: replace hardcoded coordinates with configuration - val registryAddress: String = DEFAULT_REGISTRY_ADDRESS, - private val timeProvider: ITimeProvider = SystemTimeProvider -) : DIDResolver { - - override val method = "ethr" - - override fun canResolve(potentialDID: String): Boolean { - //if it can be normalized, then it matches either an ethereum address or a full ethr-did - return normalizeDid(potentialDID).isNotBlank() - } - - /** - * Resolves a given ethereum address or DID string into a corresponding [EthrDIDDocument] - */ - override suspend fun resolve(did: String): EthrDIDDocument { - val normalizedDid = normalizeDid(did) - val identity = parseIdentity(normalizedDid) - val ethrdidContract = EthrDID(identity, rpc, registryAddress, Signer.blank) - val owner = ethrdidContract.lookupOwner(false) - val history = getHistory(identity) - return wrapDidDocument(normalizedDid, owner, history) - } - - /** - * Obtains the block number when the given identity was last changed, or [BigInteger.ZERO] if no change was ever made - */ - @VisibleForTesting(otherwise = PRIVATE) - suspend fun lastChanged(identity: String): String { - val encodedCall = EthereumDIDRegistry.Changed.encode(Solidity.Address(identity.hexToBigInteger())) - return try { - rpc.ethCall(registryAddress, encodedCall) - } catch (err: JsonRpcException) { - throw DidResolverError("Unable to evaluate when or if the $identity was lastChanged because RPC endpoint responded with an error", err) - } - } - - /** - * Builds a simple_list of events associated with the [identity] in the ether-did-registry contract that resides at [registryAddress] - * - * Since the Event classes are generated by bivrost-kotlin, they don't have a specific type so the simple_list id of type [Any] - */ - @Suppress("TooGenericExceptionCaught") - @VisibleForTesting(otherwise = PRIVATE) - suspend fun getHistory(identity: String): List { - val lastChangedQueue: Queue = PriorityQueue() - val events = emptyList().toMutableList() - lastChangedQueue.add(lastChanged(identity).hexToBigInteger()) - do { - val lastChange = lastChangedQueue.remove() - val logs = rpc.getLogs(registryAddress, listOf(null, identity.hexToBytes32()), lastChange, lastChange) - logs.forEach { - val topics: List = it.topics - val data: String = it.data - - try { - val event = EthereumDIDRegistry.Events.DIDOwnerChanged.decode(topics, data) - lastChangedQueue.add(event.previouschange.value) - events.add(event) - } catch (err: Exception) { /*nop*/ - } - - try { - val event = EthereumDIDRegistry.Events.DIDAttributeChanged.decode(topics, data) - lastChangedQueue.add(event.previouschange.value) - events.add(event) - } catch (err: Exception) { /*nop*/ - } - - try { - val event = EthereumDIDRegistry.Events.DIDDelegateChanged.decode(topics, data) - lastChangedQueue.add(event.previouschange.value) - events.add(event) - } catch (err: Exception) { /*nop*/ - } - - } - - - } while (lastChange != null && lastChange != BigInteger.ZERO) - - return events - } - - /** - * Wraps previously gathered info into a [EthrDIDDocument] - */ - @VisibleForTesting(otherwise = PRIVATE) - fun wrapDidDocument(ownerDID: String, ownerAddress: String, history: List): EthrDIDDocument { - - val pkEntries = mapOf().toMutableMap().apply { - put("owner", PublicKeyEntry( - id = "$ownerDID#owner", - type = PublicKeyType.Secp256k1VerificationKey2018, - owner = ownerDID, - ethereumAddress = ownerAddress - )) - - } - val authEntries = mapOf().toMutableMap().apply { - put("owner", AuthenticationEntry( - type = PublicKeyType.Secp256k1SignatureAuthentication2018, - publicKey = "$ownerDID#owner" - )) - } - val serviceEntries = mapOf().toMutableMap() - - var delegateCount = 0 - - history.forEach { event -> - when (event) { - is DIDDelegateChanged.Arguments -> { - val (pk, auth) = processDelegateChanged(event, delegateCount, ownerDID) - pkEntries.putAll(pk) - authEntries.putAll(auth) - delegateCount += pk.size - } - - is DIDAttributeChanged.Arguments -> { - val (pk, services) = processAttributeChanged(event, delegateCount, ownerDID) - pkEntries.putAll(pk) - serviceEntries.putAll(services) - delegateCount += pk.size - } - } - } - - return EthrDIDDocument( - id = ownerDID, - publicKey = pkEntries.values.toList(), - authentication = authEntries.values.toList(), - service = serviceEntries.values.toList() - ) - } - - private fun processAttributeChanged( - event: DIDAttributeChanged.Arguments, - delegateCount: Int, - normalizedDid: String - ): Pair, Map> { - val pkEntries = mapOf().toMutableMap() - val serviceEntries = mapOf().toMutableMap() - - var delegateIndex = delegateCount - val validTo = event.validto.value.toLong() - if (validTo < timeProvider.nowMs() / 1000L) { - return (pkEntries to serviceEntries) - } - val name = event.name.byteArray.bytes32ToString() - val key = "DIDAttributeChanged-$name-${event.value.items.toHexString()}" - - //language=RegExp - val regex = """^did/(pub|auth|svc)/(\w+)(/(\w+))?(/(\w+))?$""".toRegex() - val matchResult = regex.matchEntire(name) - ?: return (pkEntries to serviceEntries) - val (section, algo, _, rawType, _, encoding) - = matchResult.destructured - val type = parseType(algo, rawType) - - when (section) { - - "pub" -> { - delegateIndex++ - val pk = PublicKeyEntry( - id = "$normalizedDid#delegate-$delegateIndex", - type = type, - owner = normalizedDid) - - pkEntries[key] = when (encoding) { - "", "null", "hex" -> - pk.copy(publicKeyHex = event.value.items.toHexString()) - "base64" -> - pk.copy(publicKeyBase64 = event.value.items.toBase64()) - "base58" -> - pk.copy(publicKeyBase58 = event.value.items.toString(utf8).hexToByteArray().encodeToBase58String()) - else -> - pk.copy(value = event.value.items.toHexString()) - } - - } - - "svc" -> { - serviceEntries[key] = ServiceEntry( - type = algo, - serviceEndpoint = event.value.items.toString(utf8) - ) - } - } - return (pkEntries to serviceEntries) - } - - @Suppress("StringLiteralDuplication") - private fun processDelegateChanged(event: DIDDelegateChanged.Arguments, delegateCount: Int, ownerDID: String): - Pair, MutableMap> { - - val pkEntries = mapOf().toMutableMap() - val authEntries = mapOf().toMutableMap() - - var delegateIndex = delegateCount - val delegateType = event.delegatetype.bytes.toString(utf8) - val delegate = event.delegate.value.toHexStringNoPrefix().prepend0xPrefix() - val key = "DIDDelegateChanged-$delegateType-$delegate" - val validTo = event.validto.value.toLong() - - if (validTo >= timeProvider.nowMs() / 1000L) { - delegateIndex++ - - when (delegateType) { - Secp256k1SignatureAuthentication2018.name, - sigAuth -> authEntries[key] = AuthenticationEntry( - type = Secp256k1SignatureAuthentication2018, - publicKey = "$ownerDID#delegate-$delegateIndex") - - Secp256k1VerificationKey2018.name, - veriKey -> pkEntries[key] = PublicKeyEntry( - id = "$ownerDID#delegate-$delegateIndex", - type = Secp256k1VerificationKey2018, - owner = ownerDID, - ethereumAddress = delegate) - } - } - return (pkEntries to authEntries) - } - - companion object { - const val DEFAULT_REGISTRY_ADDRESS = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - - internal const val veriKey = "veriKey" - internal const val sigAuth = "sigAuth" - - private val attrTypes = mapOf( - sigAuth to "SignatureAuthentication2018", - veriKey to "VerificationKey2018" - ) - - private fun parseType(algo: String, rawType: String): PublicKeyType { - var type = if (rawType.isBlank()) veriKey else rawType - type = attrTypes[type] ?: type - return PublicKeyType("$algo$type") //will throw exception if none found - } - - //language=RegExp - val identityExtractPattern = "^did:ethr:(0x[0-9a-fA-F]{40})".toRegex() - - //language=RegExp - private val didParsePattern = "^(did:)?((\\w+):)?((0x)([0-9a-fA-F]{40}))".toRegex() - - @VisibleForTesting(otherwise = PRIVATE) - private fun parseIdentity(normalizedDid: String) = identityExtractPattern - .find(normalizedDid) - ?.destructured?.component1() ?: "" - - @VisibleForTesting(otherwise = PRIVATE) - fun normalizeDid(did: String): String { - val matchResult = didParsePattern.find(did) ?: return "" - val (didHeader, _, didType, _, _, hexDigits) = matchResult.destructured - if (didType.isNotBlank() && didType != "ethr") { - //should forward to another resolver - return "" - } - if (didHeader.isBlank() && didType.isNotBlank()) { - //doesn't really look like a did if it only specifies type and not "did:" - return "" - } - return "did:ethr:0x$hexDigits" - } - - } -} diff --git a/ethr-did/src/test/java/me/uport/sdk/ethrdid/DDOTest.kt b/ethr-did/src/test/java/me/uport/sdk/ethrdid/DDOTest.kt deleted file mode 100644 index 31273d0c..00000000 --- a/ethr-did/src/test/java/me/uport/sdk/ethrdid/DDOTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package me.uport.sdk.ethrdid - -import assertk.assert -import assertk.assertions.isEqualTo -import org.junit.Test - -class DDOTest { - - @Test - fun `can serialize minimal doc`() { - val doc = EthrDIDDocument("hello") - val docText = doc.toJson() - assert(docText).isEqualTo(""" - {"id":"hello","publicKey":[],"authentication":[],"service":[],"@context":"https://w3id.org/did/v1"} - """.trimIndent()) - } - - @Test - fun `can parse example doc`() { - //language=JSON - val docText = """ - { - "@context": "https://w3id.org/did/v1", - "id": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "publicKey": [{ - "id": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner", - "type" : "Secp256k1VerificationKey2018", - "owner" : "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "ethereumAddress" : "0xb9c5714089478a327f09197987f16f9e5d936e8a" - }], - "authentication": [{ - "type": "Secp256k1SignatureAuthentication2018", - "publicKey": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner" - }] - } - """.trimIndent() - - assert { - EthrDIDDocument.fromJson(docText) - }.doesNotThrowAnyException() - - } - -} \ No newline at end of file diff --git a/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDResolverTest.kt b/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDResolverTest.kt deleted file mode 100644 index a60623f3..00000000 --- a/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDResolverTest.kt +++ /dev/null @@ -1,262 +0,0 @@ -@file:Suppress("UnnecessaryVariable") - -package me.uport.sdk.ethrdid - -import assertk.all -import assertk.assert -import assertk.assertions.hasSize -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan -import assertk.assertions.isNotEmpty -import assertk.assertions.isNotEqualTo -import assertk.assertions.isNotNull -import io.mockk.coEvery -import io.mockk.mockk -import io.mockk.slot -import io.mockk.spyk -import kotlinx.coroutines.runBlocking -import me.uport.sdk.core.HttpClient -import me.uport.sdk.core.Networks -import me.uport.sdk.core.hexToBytes32 -import me.uport.sdk.core.utf8 -import me.uport.sdk.ethrdid.EthereumDIDRegistry.Events.DIDOwnerChanged -import me.uport.sdk.jsonrpc.JsonRPC -import me.uport.sdk.jsonrpc.JsonRpcLogItem -import org.junit.Test -import org.kethereum.extensions.hexToBigInteger -import pm.gnosis.model.Solidity -import pm.gnosis.utils.hexToByteArray -import java.math.BigInteger - - -class EthrDIDResolverTest { - - @Test - fun `last change is blank for new address`() = runBlocking { - val rpc = spyk(JsonRPC(Networks.rinkeby.rpcUrl)) - val encodedCallSlot = slot() - - coEvery { rpc.ethCall(any(), capture(encodedCallSlot)) } returns "0x0000000000000000000000000000000000000000000000000000000000000000" - - val imaginaryAddress = "0x1234" - val lastChanged = EthrDIDResolver(rpc).lastChanged(imaginaryAddress) - - assert(encodedCallSlot.captured).isEqualTo("0xf96d0f9f0000000000000000000000000000000000000000000000000000000000001234") - assert(lastChanged.hexToBigInteger()).isEqualTo(BigInteger.ZERO) - } - - @Test - fun `last change is non-zero for real address with changed owner`() = runBlocking { - val rpc = spyk(JsonRPC(Networks.rinkeby.rpcUrl)) - val encodedCallSlot = slot() - coEvery { rpc.ethCall(any(), capture(encodedCallSlot)) } returns "0x00000000000000000000000000000000000000000000000000000000002a8a7d" - - val realAddress = "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" - val lastChanged = EthrDIDResolver(rpc).lastChanged(realAddress) - - assert(encodedCallSlot.captured).isEqualTo("0xf96d0f9f000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74") - assert(lastChanged.hexToBigInteger()).isNotEqualTo(BigInteger.ZERO) - } - - - @Test - fun `can parse getLogs response`() = runBlocking { - val http = mockk() - val rpc = JsonRPC(Networks.rinkeby.rpcUrl, http) - val realAddress = "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" - val resolver = EthrDIDResolver(rpc) - val lastChanged = "0x00000000000000000000000000000000000000000000000000000000002a8a7d".hexToBigInteger() - - //language=json - val cannedLogsResponse = """{"jsonrpc":"2.0","id":1,"result":[{"address":"0xdca7ef03e98e0dc2b855be647c39abe984fcf21b","blockHash":"0x10b9345e8c8ba8f5fbd164fc104e4959abb010ddcc38b164ac1c62c55e75856e","blockNumber":"0x2a8a7d","data":"0x536563703235366b31566572696669636174696f6e4b6579323031380000000000000000000000000000000045c4ebd7ffb86891ba6f9f68452f9f0815aacd8b0000000000000000000000000000000000000000000000000000000117656a2f00000000000000000000000000000000000000000000000000000000002a7b24","logIndex":"0x16","removed":false,"topics":["0x5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f7","0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74"],"transactionHash":"0x59180d9f3257a538ef77ba7363ec55ed76b609bf0c90cdf7fb710d695ebaa5c0","transactionIndex":"0x17"}]}""" - coEvery { http.urlPost(any(), any(), any()) } returns cannedLogsResponse - - val logResponse = rpc.getLogs(resolver.registryAddress, listOf(null, realAddress.hexToBytes32()), lastChanged, lastChanged) - - assert(logResponse).all { - isNotNull() - isNotEmpty() - } - } - - @Test - fun `can parse owner changed logs`() = runBlocking { - val logItem = JsonRpcLogItem( - address = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b", - topics = listOf("0x38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a3", - "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74"), - data = "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74000000000000000000000000000000000000000000000000000000000029db37", - blockNumber = BigInteger("2784036"), - transactionHash = "0xb42e3fbf29fffe53746021837396cf1a2e9ad88a82d5c9213e2725b5e72e123e", - transactionIndex = BigInteger("17"), - blockHash = "0xf7b8a4b602e6e47fc190ecbb213d09cd577186b3d2f28a0816eff6da55a6e469", - logIndex = BigInteger("20"), - removed = false) - - val topics: List = logItem.topics - val data: String = logItem.data - val args: DIDOwnerChanged.Arguments = DIDOwnerChanged.decode(topics, data) - //no assertion about args but it should not crash - val previousBlock = args.previouschange.value - - assert(previousBlock).isGreaterThan(BigInteger.ZERO) - } - - @Test - fun `can parse multiple event logs`() = runBlocking { - val realAddress = "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" - - val rpc = spyk(JsonRPC(Networks.rinkeby.rpcUrl)) - coEvery { rpc.ethCall(any(), eq("0xf96d0f9f000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74")) } - .returns("0x00000000000000000000000000000000000000000000000000000000002a8a7d") - val cannedResponses: List> = listOf( - listOf(JsonRpcLogItem(address = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b", blockHash = "0x10b9345e8c8ba8f5fbd164fc104e4959abb010ddcc38b164ac1c62c55e75856e", blockNumber = "0x2a8a7d".hexToBigInteger(), data = "0x536563703235366b31566572696669636174696f6e4b6579323031380000000000000000000000000000000045c4ebd7ffb86891ba6f9f68452f9f0815aacd8b0000000000000000000000000000000000000000000000000000000117656a2f00000000000000000000000000000000000000000000000000000000002a7b24", logIndex = "0x16".hexToBigInteger(), removed = false, topics = listOf("0x5a5084339536bcab65f20799fcc58724588145ca054bd2be626174b27ba156f7", "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74"), transactionHash = "0x59180d9f3257a538ef77ba7363ec55ed76b609bf0c90cdf7fb710d695ebaa5c0", transactionIndex = "0x17".hexToBigInteger())), - listOf(JsonRpcLogItem(address = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b", blockHash = "0xf7b8a4b602e6e47fc190ecbb213d09cd577186b3d2f28a0816eff6da55a6e469", blockNumber = "0x2a7b24".hexToBigInteger(), data = "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74000000000000000000000000000000000000000000000000000000000029db37", logIndex = "0x14".hexToBigInteger(), removed = false, topics = listOf("0x38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a3", "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74"), transactionHash = "0xb42e3fbf29fffe53746021837396cf1a2e9ad88a82d5c9213e2725b5e72e123e", transactionIndex = "0x11".hexToBigInteger())), - listOf(JsonRpcLogItem(address = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b", blockHash = "0xf0bfb1aaa47ce10e6aa99940bafc2bb11f3de742d44d2288b4546250e67b0971", blockNumber = "0x29db37".hexToBigInteger(), data = "0x00000000000000000000000045c4ebd7ffb86891ba6f9f68452f9f0815aacd8b0000000000000000000000000000000000000000000000000000000000000000", logIndex = "0x0".hexToBigInteger(), removed = false, topics = listOf("0x38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a3", "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74"), transactionHash = "0x70829b62ac232269a0524b180054532eff18b5fbc60b7102b6120844b5cdb1d8", transactionIndex = "0x1".hexToBigInteger())), - emptyList() - ) - coEvery { rpc.getLogs(any(), any(), any(), any()) }.returnsMany(cannedResponses) - - val resolver = EthrDIDResolver(rpc) - val events = resolver.getHistory(realAddress) - assert(events).hasSize(3) - } - - // "did/pub/(Secp256k1|Rsa|Ed25519)/(veriKey|sigAuth)/(hex|base64)", - private val attributeRegexes = listOf( - "did/pub/Secp256k1/veriKey/hex", - "did/pub/Rsa/veriKey/hex", - "did/pub/Ed25519/veriKey/hex", - "did/pub/Secp256k1/sigAuth/hex", - "did/pub/Rsa/sigAuth/hex", - "did/pub/Ed25519/sigAuth/hex", - "did/pub/Secp256k1/veriKey/base64", - "did/pub/Rsa/veriKey/base64", - "did/pub/Ed25519/veriKey/base64", - "did/pub/Secp256k1/sigAuth/base64", - "did/pub/Rsa/sigAuth/base64", - "did/pub/Ed25519/sigAuth/base64", - "did/pub/Secp256k1/veriKey", - "did/pub/Rsa/veriKey", - "did/pub/Ed25519/veriKey", - "did/pub/Secp256k1/sigAuth", - "did/pub/Rsa/sigAuth", - "did/pub/Ed25519/sigAuth", - "did/pub/Secp256k1", - "did/pub/Rsa", - "did/pub/Ed25519" - ) - - @Suppress("UNUSED_VARIABLE") - @Test - fun `can parse attribute regex`() { - val regex = "^did/(pub|auth|svc)/(\\w+)(/(\\w+))?(/(\\w+))?$".toRegex() - attributeRegexes.forEach { - val matchResult = regex.find(it) - - assert(matchResult).isNotNull() - - val (section, algo, _, rawType, _, encoding) = matchResult!!.destructured - - assert(section).isNotEmpty() - assert(algo).isNotEmpty() - } - } - - @Test - fun `can parse sample attr change event`() { - val soon = System.currentTimeMillis() / 1000 + 600 - val identity = "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" - val owner = identity - - val event = EthereumDIDRegistry.Events.DIDAttributeChanged.Arguments( - identity = Solidity.Address(identity.hexToBigInteger()), - name = Solidity.Bytes32("did/pub/Secp256k1/veriKey/base64".toByteArray()), - value = Solidity.Bytes("0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71".hexToByteArray()), - validto = Solidity.UInt256(soon.toBigInteger()), - previouschange = Solidity.UInt256(BigInteger.ZERO) - ) - - val rpc = JsonRPC(Networks.rinkeby.rpcUrl) - - assert { - EthrDIDResolver(rpc).wrapDidDocument("did:ethr:$identity", owner, listOf(event)) - }.doesNotThrowAnyException() - } - - @Test - fun `to and from solidity bytes`() { - val str = "did/pub/Secp256k1/veriKey/hex" - val sol = Solidity.Bytes32(str.toByteArray()) - val decodedStr = sol.bytes.toString(utf8) - assert(decodedStr).isEqualTo(str) - } - - @Test - fun `can resolve real did`() = runBlocking { - val http = mockk() - - //language=JSON - val referenceDDOString = """ - { - "@context": "https://w3id.org/did/v1", - "id": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "publicKey": [{ - "id": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner", - "type": "Secp256k1VerificationKey2018", - "owner": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "ethereumAddress": "0xb9c5714089478a327f09197987f16f9e5d936e8a"}], - "authentication": [{ - "type": "Secp256k1SignatureAuthentication2018", - "publicKey": "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a#owner"}] - } - """.trimIndent() - val referenceDDO = EthrDIDDocument.fromJson(referenceDDOString) - - val addressHex = "b9c5714089478a327f09197987f16f9e5d936e8a" - - val rpc = spyk(JsonRPC(Networks.rinkeby.rpcUrl, http)) - //canned response for get owner query - coEvery { rpc.ethCall(any(), eq("0x8733d4e8000000000000000000000000$addressHex")) } returns "0x000000000000000000000000$addressHex" - //canned response for last changed query - coEvery { rpc.ethCall(any(), eq("0xf96d0f9f000000000000000000000000$addressHex")) } returns "0x0000000000000000000000000000000000000000000000000000000000000000" - //canned response for getLogs - coEvery { http.urlPost(any(), any(), any()) } returns """{"jsonrpc":"2.0","id":1,"result":[]}""" - - val resolver = EthrDIDResolver(rpc) - val ddo = resolver.resolve("did:ethr:0x$addressHex") - assert(ddo).isEqualTo(referenceDDO) - } - - @Test - fun `can normalize DID`() { - - val validDids = listOf( - "0xb9c5714089478a327f09197987f16f9e5d936e8a", - "0xB9C5714089478a327F09197987f16f9E5d936E8a", - "did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "did:ethr:0xB9C5714089478a327F09197987f16f9E5d936E8a", - "did:ethr:0xB9C5714089478a327F09197987f16f9E5d936E8a#owner" - ) - - val invalidDids = listOf( - "0xb9c5714089478a327f09197987f16f9e5d936e", - "B9C5714089478a327F09197987f16f9E5d936E8a", - "ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a", - "B9C5714089478a327F09197987f16f9E5d936E8a", - "B9C5714089478a327F09197987f16f9E5d936E" - ) - - validDids.forEach { - val normalizedDid = EthrDIDResolver.normalizeDid(it) - assert(normalizedDid.toLowerCase()).isEqualTo("did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a") - } - - invalidDids.forEach { - val normalizedDid = EthrDIDResolver.normalizeDid(it) - assert(normalizedDid).isEmpty() - } - } - -} diff --git a/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDTest.kt b/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDTest.kt deleted file mode 100644 index 43c693d3..00000000 --- a/ethr-did/src/test/java/me/uport/sdk/ethrdid/EthrDIDTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -@file:Suppress("UNCHECKED_CAST", "unused", "MemberVisibilityCanBePrivate") - -package me.uport.sdk.ethrdid - -import assertk.assert -import assertk.assertions.isEqualTo -import com.uport.sdk.signer.KPSigner -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import me.uport.sdk.jsonrpc.JsonRPC -import org.junit.Test -import org.walleth.khex.prepend0xPrefix -import java.math.BigInteger - -class EthrDIDTest { - - val originalPrivKey = "278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f" - val originalAddress = "0xf3beac30c498d9e26865f34fcaa57dbb935b0d74" - - val newPrivKey = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38" - val newAddress = "0x45c4EBd7Ffb86891BA6f9F68452F9F0815AAcD8b" - - val rinkebyRegistry = "0xdca7ef03e98e0dc2b855be647c39abe984fcf21b" - - @Test - fun `lookup owner works for new identity`() { - - val rpc = mockk() { - coEvery { ethCall(any(), any()) } returns "0x0000000000000000000000001122334455667788990011223344556677889900" - } - val ethrDid = EthrDID("0x11", rpc, rinkebyRegistry, KPSigner(originalPrivKey)) - val owner = runBlocking { - ethrDid.lookupOwner() - } - assert(owner).isEqualTo("0x1122334455667788990011223344556677889900") - } - - @Test - fun `change owner sends proper transaction`() { - - runBlocking { - - val signer = KPSigner(originalPrivKey) - val address = signer.getAddress().prepend0xPrefix() - - val rpc = mockk { - coEvery { getTransactionCount(any()) } returns BigInteger.ZERO - coEvery { getGasPrice() } returns 20_000_000_000L.toBigInteger() - coEvery { ethCall(any(), any()) } returns "0x0000000000000000000000001122334455667788990011223344556677889900" - coEvery { sendRawTransaction(any()) } returns "mockedTxHash" - } - - val ethrDid = EthrDID(address, rpc, rinkebyRegistry, signer) - - val txHash = ethrDid.changeOwner(newAddress) - - assert(txHash).isEqualTo("mockedTxHash") - - val expectedSignedTx = "0xf8aa808504a817c8008301117094dca7ef03e98e0dc2b855be647c39abe984fcf21b80b844f00d4b5d000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d7400000000000000000000000045c4ebd7ffb86891ba6f9f68452f9f0815aacd8b1ca0eb687cc4a323d4c3471d01d3a0d3d212754539fa9d2f6973acc0f1de275f53e9a0257684845b8d3d5e0c0838c5da007ddc7a0df08722fba53866601821f0aceff4" - - coVerify { - rpc.sendRawTransaction(eq(expectedSignedTx)) - } - - } - } -} \ No newline at end of file diff --git a/fuelingservice/build.gradle b/fuelingservice/build.gradle index a7684adb..c2f455d0 100644 --- a/fuelingservice/build.gradle +++ b/fuelingservice/build.gradle @@ -24,16 +24,15 @@ android { } dependencies { - implementation( - "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version", - "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version", - "com.google.firebase:firebase-iid:$play_services_version", + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + implementation "com.android.support:appcompat-v7:$support_lib_version" + implementation "com.google.firebase:firebase-iid:$firebase_iid_version" + implementation "com.squareup.okhttp3:okhttp:$okhttp_version" + implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" - "com.squareup.okhttp3:okhttp:$okhttp_version", - "com.squareup.okhttp3:logging-interceptor:$okhttp_version", + api "com.github.uport-project.kotlin-common:core:$kotlin_common_version" - project(":core") - ) testImplementation "junit:junit:$junit_version" androidTestImplementation "com.android.support.test:runner:$test_runner_version" } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f348ebaa..acb8c473 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,9 +10,10 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +android.enableUnitTestBinaryResources=true org.gradle.parallel=true -android.enableUnitTestBinaryResources=true \ No newline at end of file +org.gradle.caching=true +org.gradle.configureondemand=true + +kotlin.code.style=official +kotlin.incremental=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b971f986..e8753738 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/https-did/.gitignore b/https-did/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/https-did/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/https-did/build.gradle b/https-did/build.gradle deleted file mode 100644 index ce5f0fc1..00000000 --- a/https-did/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlinx-serialization' -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "resolver for the https-did method" - -android { - compileSdkVersion compile_sdk_version - buildToolsVersion build_tools_version - - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - multiDexEnabled true - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - dexOptions { - jumboMode true - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - - api project(":jsonrpc") - api project(":core") - api project(":universal-did") - - testImplementation "junit:junit:$junit_version" - testImplementation "io.mockk:mockk:$mockk_version" - testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" - testImplementation project(":test-helpers") -} diff --git a/https-did/proguard-rules.pro b/https-did/proguard-rules.pro deleted file mode 100644 index f1b42451..00000000 --- a/https-did/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/https-did/src/main/AndroidManifest.xml b/https-did/src/main/AndroidManifest.xml deleted file mode 100644 index 77557c08..00000000 --- a/https-did/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDDocument.kt b/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDDocument.kt deleted file mode 100644 index ca63902d..00000000 --- a/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDDocument.kt +++ /dev/null @@ -1,48 +0,0 @@ -package me.uport.sdk.httpsdid - -import kotlinx.serialization.Optional -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import me.uport.sdk.universaldid.AuthenticationEntry -import me.uport.sdk.universaldid.DIDDocument -import me.uport.sdk.universaldid.PublicKeyEntry -import me.uport.sdk.universaldid.ServiceEntry - -/** - * Encapsulates the fields of a Decentralized Identity Document - */ -@Serializable -data class HttpsDIDDocument( - @SerialName("@context") - override val context: String = "https://w3id.org/did/v1", - - @SerialName("id") - override val id: String, //ex: "did:https:example.com#owner" - - @SerialName("publicKey") - override val publicKey: List = emptyList(), - - @SerialName("authentication") - override val authentication: List = emptyList(), - - @Optional - @SerialName("service") - override val service: List = emptyList() - -) : DIDDocument { - - /** - * Serializes this [HttpsDIDDocument] into a JSON string - */ - fun toJson(): String = Json.stringify(HttpsDIDDocument.serializer(), this) - - companion object { - - /** - * Attempts to deserialize a given [json] string into a [HttpsDIDDocument] - */ - fun fromJson(json: String) = Json.nonstrict.parse(HttpsDIDDocument.serializer(), json) - } - -} \ No newline at end of file diff --git a/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDResolver.kt b/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDResolver.kt deleted file mode 100644 index 0f1935de..00000000 --- a/https-did/src/main/java/me/uport/sdk/httpsdid/HttpsDIDResolver.kt +++ /dev/null @@ -1,51 +0,0 @@ -package me.uport.sdk.httpsdid - -import me.uport.sdk.core.HttpClient -import me.uport.sdk.universaldid.BlankDocumentError -import me.uport.sdk.universaldid.DIDResolver -import me.uport.sdk.universaldid.DidResolverError - -/** - * This is a DID resolver implementation that supports the "https" DID method. - * It accepts https-did strings and produces a document described at: - * https://w3c-ccg.github.io/did-spec/#did-documents - * - * Example https did: "did:https:example.com" - */ -open class HttpsDIDResolver(private val httpClient: HttpClient = HttpClient()) : DIDResolver { - override val method: String = "https" - - override suspend fun resolve(did: String): HttpsDIDDocument { - if (canResolve(did)) { - val (_, domain) = parseDIDString(did) - val ddoString = getProfileDocument(domain) - if (ddoString.isBlank()) { - throw BlankDocumentError("no profile document found for `$did`") - } - return HttpsDIDDocument.fromJson(ddoString) - } else { - throw DidResolverError("The DID('$did') cannot be resolved by the HTTPS DID resolver") - } - } - - override fun canResolve(potentialDID: String): Boolean { - val (method, _) = parseDIDString(potentialDID) - return (method == this.method) - } - - - private suspend fun getProfileDocument(domain: String): String { - val url = "https://$domain/.well-known/did.json" - return httpClient.urlGet(url) - } - - companion object { - private val uportDIDPattern = "^(did:(https):)?([-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])".toRegex() - - internal fun parseDIDString(did: String): Pair { - val matchResult = uportDIDPattern.find(did) ?: return ("" to did) - val (_, method, domain) = matchResult.destructured - return (method to domain) - } - } -} \ No newline at end of file diff --git a/https-did/src/test/java/me/uport/sdk/httpsdid/HttpsDIDResolverTest.kt b/https-did/src/test/java/me/uport/sdk/httpsdid/HttpsDIDResolverTest.kt deleted file mode 100644 index 181d9de9..00000000 --- a/https-did/src/test/java/me/uport/sdk/httpsdid/HttpsDIDResolverTest.kt +++ /dev/null @@ -1,87 +0,0 @@ -package me.uport.sdk.httpsdid - -import assertk.assert -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import io.mockk.coEvery -import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.SerializationException -import me.uport.sdk.core.HttpClient -import me.uport.sdk.testhelpers.coAssert -import me.uport.sdk.testhelpers.isInstanceOf -import me.uport.sdk.universaldid.AuthenticationEntry -import me.uport.sdk.universaldid.DidResolverError -import me.uport.sdk.universaldid.PublicKeyEntry -import me.uport.sdk.universaldid.PublicKeyType -import org.junit.Test -import java.io.IOException - -class HttpsDIDResolverTest { - - private val exampleDidDoc = HttpsDIDDocument(context = "https://w3id.org/did/v1", - id = "did:https:example.com", - publicKey = listOf( - PublicKeyEntry(id = "did:https:example.com", - type = PublicKeyType.Secp256k1VerificationKey2018, - owner = "did:https:example.com", - ethereumAddress = "0x3c7d65d6daf5df62378874d35fa3626100af9d85" - ) - ), - authentication = listOf( - AuthenticationEntry(type = PublicKeyType.Secp256k1SignatureAuthentication2018, - publicKey = "did:https:example.com#owner") - ), - service = emptyList() - ) - - - @Test - fun `can resolve valid dids`() { - listOf( - "did:https:example.com", - "did:https:example.ngrok.com#owner" - ).forEach { - assert(HttpsDIDResolver().canResolve(it)) - } - - } - - @Test - fun `fails on invalid dids`() { - listOf( - "did:something:example.com", //different method - "example.com" - ).forEach { - assert(HttpsDIDResolver().canResolve(it)).isFalse() - } - } - - @Test - fun `fails when the endpoint doesn't provide a DID document`() = runBlocking { - val http = mockk() - val tested = HttpsDIDResolver(http) - coEvery { http.urlGet(any()) } returns "" - - coAssert { - tested.resolve("did:https:example.com") - }.thrownError { - isInstanceOf(listOf(IllegalArgumentException::class, IOException::class, SerializationException::class, DidResolverError::class)) - } - } - - @Test - fun `resolves document`() = runBlocking { - - val http = mockk() - val tested = HttpsDIDResolver(http) - - coEvery { http.urlGet(any()) } returns exampleDidDoc.toJson() - - val response = tested.resolve("did:https:example.com") - assert(response).isEqualTo(exampleDidDoc) - } - -} - - diff --git a/identity/build.gradle b/identity/build.gradle index 632ce551..09239e1f 100644 --- a/identity/build.gradle +++ b/identity/build.gradle @@ -9,8 +9,6 @@ project.ext.description = "classes for creating and managing uPort Account objec android { compileSdkVersion compile_sdk_version - - defaultConfig { minSdkVersion min_sdk_version targetSdkVersion target_sdk_version @@ -18,7 +16,6 @@ android { versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - multiDexEnabled = true } buildTypes { @@ -26,21 +23,23 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + + debug { + multiDexEnabled = true + } } } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialization_version" implementation "com.android.support:support-annotations:$support_lib_version" - api "com.github.walleth.kethereum:model:$kethereum_version" - api project(':uport-did') - api project(':ethr-did') - api project(":core") - api project(":signer") - api project(":serialization") + api "com.github.komputing.KEthereum:model:$kethereum_version" + api "com.github.uport-project.kotlin-common:core:$kotlin_common_version" + api "com.github.uport-project:uport-android-signer:$uport_signer_version" androidTestImplementation "com.android.support.test:runner:$test_runner_version" androidTestImplementation "com.android.support.test:rules:$test_runner_version" @@ -48,4 +47,7 @@ dependencies { testImplementation "junit:junit:$junit_version" testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" -} \ No newline at end of file + testImplementation "com.github.uport-project.kotlin-common:jsonrpc:$kotlin_common_version" + testImplementation "com.github.uport-project.kotlin-did-jwt:ethr-did:$did_jwt_version" + testImplementation "com.github.uport-project.kotlin-did-jwt:uport-did:$did_jwt_version" +} diff --git a/identity/src/androidTest/java/me/uport/sdk/identity/KPAccountCreatorTest.kt b/identity/src/androidTest/java/me/uport/sdk/identity/HDAccountCreatorTest.kt similarity index 53% rename from identity/src/androidTest/java/me/uport/sdk/identity/KPAccountCreatorTest.kt rename to identity/src/androidTest/java/me/uport/sdk/identity/HDAccountCreatorTest.kt index 6d9167f6..3290d971 100644 --- a/identity/src/androidTest/java/me/uport/sdk/identity/KPAccountCreatorTest.kt +++ b/identity/src/androidTest/java/me/uport/sdk/identity/HDAccountCreatorTest.kt @@ -3,7 +3,7 @@ package me.uport.sdk.identity import android.content.Context import android.support.test.InstrumentationRegistry import assertk.all -import assertk.assert +import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNotEmpty import assertk.assertions.isNotEqualTo @@ -14,7 +14,7 @@ import org.junit.Before import org.junit.Test //TODO: move this to JVM test with robolectric once a solution is found for https://github.com/robolectric/robolectric/issues/1518 -class KPAccountCreatorTest { +class HDAccountCreatorTest { private lateinit var appContext: Context @@ -26,16 +26,16 @@ class KPAccountCreatorTest { @Test fun createAccount() { runBlocking { - val account = KPAccountCreator(appContext).createAccount(Networks.rinkeby.networkId) + val account = HDAccountCreator(appContext).createAccount(Networks.rinkeby.networkId) - assert(account).all { + assertThat(account).all { isNotNull() - isNotEqualTo(Account.blank) + isNotEqualTo(HDAccount.blank) } - assert(account.type).isEqualTo(AccountType.KeyPair) - assert(account.address).isNotEmpty() - assert(account.publicAddress).isNotEmpty() - assert(account.deviceAddress).isNotEmpty() + + assertThat(account.address).isNotEmpty() + assertThat(account.publicAddress).isNotEmpty() + assertThat(account.deviceAddress).isNotEmpty() } } @@ -45,16 +45,15 @@ class KPAccountCreatorTest { val referenceSeedPhrase = "vessel ladder alter error federal sibling chat ability sun glass valve picture" runBlocking { - val account = KPAccountCreator(appContext).importAccount(Networks.rinkeby.networkId, referenceSeedPhrase) - assert(account).all { + val account = HDAccountCreator(appContext).importAccount(Networks.rinkeby.networkId, referenceSeedPhrase) + assertThat(account).all { isNotNull() - isNotEqualTo(Account.blank) + isNotEqualTo(HDAccount.blank) } - assert(account.type).isEqualTo(AccountType.KeyPair) - assert(account.address).isEqualTo("2opxPamUQoLarQHAoVDKo2nDNmfQLNCZif4") - assert(account.publicAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") - assert(account.deviceAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") - assert(account.handle).isEqualTo("0x794adde0672914159c1b77dd06d047904fe96ac8") + assertThat(account.address).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.publicAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.deviceAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.handle).isEqualTo("0x794adde0672914159c1b77dd06d047904fe96ac8") } } } \ No newline at end of file diff --git a/identity/src/main/java/me/uport/sdk/identity/Account.kt b/identity/src/main/java/me/uport/sdk/identity/Account.kt index 816e5f0f..4b4889cd 100644 --- a/identity/src/main/java/me/uport/sdk/identity/Account.kt +++ b/identity/src/main/java/me/uport/sdk/identity/Account.kt @@ -1,87 +1,55 @@ +@file:Suppress("unused") + package me.uport.sdk.identity import android.content.Context -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE -import com.uport.sdk.signer.Signer -import com.uport.sdk.signer.UportHDSigner -import com.uport.sdk.signer.UportHDSignerImpl -import kotlinx.serialization.Optional -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import kotlinx.serialization.json.Json -import me.uport.mnid.MNID - -@Serializable -data class Account( - - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - @SerialName("uportRoot") - val handle: String, - - @SerialName("devKey") - val deviceAddress: String, - - @SerialName("network") - val network: String, - - @SerialName("proxy") - val publicAddress: String, - - @SerialName("manager") - val identityManagerAddress: String, - - @SerialName("txRelay") - val txRelayAddress: String, - - @SerialName("fuelToken") - val fuelToken: String, - - @SerialName("signerType") - val type: AccountType = AccountType.KeyPair, - - @Optional - @SerialName("isDefault") - val isDefault: Boolean? = false -) { - - @Transient - val address: String - get() = getMnid() - - fun getMnid() = MNID.encode(network, publicAddress) +import me.uport.sdk.signer.Signer - fun toJson(pretty: Boolean = false): String = if (pretty) Json.indented.stringify(Account.serializer(), this) else Json.stringify(Account.serializer(), this) +/** + * Abstraction of the common properties and methods for various account types + * + * Each account implement this interface, then override its properties and methods + */ +interface Account { - fun getSigner(context: Context): Signer = UportHDSignerImpl(context, UportHDSigner(), rootAddress = handle, deviceAddress = deviceAddress) + /** + * Represents an alias to the account. + * This [handle] will be used to refer to and interact with the [Account] + */ + val handle: String /** - * This function generates the DID associated with an account based on the account type. - * - * Limitation: The current implementation only covers KeyPair and MetaIdentity Account types - * @returns the DID as a string - * @throws IllegalStateException if there is no implementation for the Account Type + * Represents the ethereum address that signs transactions. + * This address is derived from a private key that this [Account] can control + * (as opposed to it representing an external entity with an unknown key). */ - fun getDID(): String { - return when (type) { - AccountType.MetaIdentityManager -> "did:uport:${getMnid()}" - AccountType.KeyPair -> "did:ethr:$publicAddress" - else -> throw IllegalStateException("A DID could not be created for the Account Type $type") - } - } + val deviceAddress: String - companion object { + /** + * The network ID this account is associated with. + */ + val network: String - val blank = Account("", "", "", "", "", "", "", AccountType.KeyPair) + /** + * Represents the public facing address of this [Account]. + * In most cases this is identical to the [deviceAddress] or an encoding of it, + * but it can also represent a contract address + * or an address of a key that is not directly controlled by this [Account]. + */ + val publicAddress: String - fun fromJson(serializedAccount: String?): Account? { - if (serializedAccount == null || serializedAccount.isEmpty()) { - return null - } + /** + * The type of signer that is backing this Account + */ + val type: AccountType - return Json.parse(Account.serializer(), serializedAccount) - } - } + /** + * this will return the [Signer] of the implementing account + */ + fun getSigner(context: Context): Signer -} \ No newline at end of file + /** + * this will return the DID associated with the implementing account + */ + fun getDID(): String +} diff --git a/identity/src/main/java/me/uport/sdk/identity/AccountCreator.kt b/identity/src/main/java/me/uport/sdk/identity/AccountCreator.kt index 66ae86a3..2bb61450 100644 --- a/identity/src/main/java/me/uport/sdk/identity/AccountCreator.kt +++ b/identity/src/main/java/me/uport/sdk/identity/AccountCreator.kt @@ -1,20 +1,18 @@ package me.uport.sdk.identity -typealias AccountCreatorCallback = (err: Exception?, acc: Account) -> Unit - /** - * Interface describing an [Account] manager that can create, import and delete accounts + * Interface describing an account manager that can create, import and delete accounts */ interface AccountCreator { /** - * Create an [Account] rooted in a given [networkId]. + * Create an account rooted in a given [networkId]. * The process can be restarted if [forceRecreate] is set to true */ suspend fun createAccount(networkId: String, forceRecreate: Boolean = false): Account /** - * Create an [Account] rooted in a given [networkId] and based on a seed phrase + * Create an account rooted in a given [networkId] and based on a seed phrase * The process can be restarted if [forceRecreate] is set to true */ suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean = false): Account diff --git a/identity/src/main/java/me/uport/sdk/identity/AccountType.kt b/identity/src/main/java/me/uport/sdk/identity/AccountType.kt index 2c25a853..6f6a6a30 100644 --- a/identity/src/main/java/me/uport/sdk/identity/AccountType.kt +++ b/identity/src/main/java/me/uport/sdk/identity/AccountType.kt @@ -1,12 +1,55 @@ package me.uport.sdk.identity -import android.support.annotation.Keep - -@Keep +/** + * This encapsulates types of [Account]s with regard to the algorithms used to sign transactions. + * + */ enum class AccountType { + + /** + * This [Account] is backed by a key pair that resides in memory. + * Transactions are signed directly by this key pair. + */ KeyPair, + + /** + * This [Account] is backed by a key pair derived from a seed. + * Transactions are signed directly by this derived key pair. + */ + HDKeyPair, + + /** + * This [Account] is backed by a proxy contract that is controlled + * through a MetaIdentityManager, supporting meta-transactions. + * The signer used by this Account needs to wrap a key pair signer. + * Transactions are signed by a key that is authorized to control the proxy and + * the check is made by the meta-identity-manager contract. + */ MetaIdentityManager, + + /** + * This Account is backed by a Proxy contract. + * This is not directly used. + * Please use [MetaIdentityManager] instead. + */ Proxy, + + /** + * This [Account] is backed by a key pair that is only present on this device. + * This is deprecated, please use a [KeyPair] + */ + @Deprecated("please use KeyPair instead", ReplaceWith("KeyPair")) Device, + + /** + * This [Account] is backed by a proxy contract that is controlled + * through an IdentityManager contract. + * The signer used by this Account needs to wrap a key pair signer. + * Transactions are signed by a key that is authorized to control the proxy and + * the check is made by the meta-identity-manager contract. + * + * This is deprecated, please use a [MetaIdentityManager] + */ + @Deprecated("please use MetaIdentityManager instead", ReplaceWith("MetaIdentityManager")) IdentityManager, -} \ No newline at end of file +} diff --git a/identity/src/main/java/me/uport/sdk/identity/HDAccount.kt b/identity/src/main/java/me/uport/sdk/identity/HDAccount.kt new file mode 100644 index 00000000..27ae6212 --- /dev/null +++ b/identity/src/main/java/me/uport/sdk/identity/HDAccount.kt @@ -0,0 +1,68 @@ +package me.uport.sdk.identity + +import android.content.Context +import android.support.annotation.VisibleForTesting +import com.uport.sdk.signer.UportHDSigner +import com.uport.sdk.signer.UportHDSignerImpl +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.json.Json +import me.uport.sdk.signer.Signer + +/** + * This is an [Account] implementation that is backed by a key pair derived from a seed. + */ +@Serializable +data class HDAccount( + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + @SerialName("uportRoot") + override val handle: String, + + @SerialName("devKey") + override val deviceAddress: String, + + @SerialName("network") + override val network: String, + + @SerialName("proxy") + override val publicAddress: String, + + @SerialName("signerType") + override val type: AccountType = AccountType.HDKeyPair + +) : Account { + + @Transient + val address: String + get() = publicAddress + + /** + * serializes account + */ + fun toJson(pretty: Boolean = false): String = if (pretty) Json.indented.stringify(serializer(), this) else Json.stringify(serializer(), this) + + override fun getSigner(context: Context): Signer = UportHDSignerImpl(context, UportHDSigner(), rootAddress = handle, deviceAddress = deviceAddress) + + /** + * This function generates and returns the DID associated with an account + */ + override fun getDID(): String = "did:ethr:$publicAddress" + + companion object { + + val blank = HDAccount("", "", "", "") + + /** + * de-serializes account + */ + fun fromJson(serializedAccount: String?): HDAccount? { + if (serializedAccount == null || serializedAccount.isEmpty()) { + return null + } + + return Json.nonstrict.parse(serializer(), serializedAccount) + } + } +} diff --git a/identity/src/main/java/me/uport/sdk/identity/KPAccountCreator.kt b/identity/src/main/java/me/uport/sdk/identity/HDAccountCreator.kt similarity index 78% rename from identity/src/main/java/me/uport/sdk/identity/KPAccountCreator.kt rename to identity/src/main/java/me/uport/sdk/identity/HDAccountCreator.kt index 97642336..8150c34c 100644 --- a/identity/src/main/java/me/uport/sdk/identity/KPAccountCreator.kt +++ b/identity/src/main/java/me/uport/sdk/identity/HDAccountCreator.kt @@ -9,16 +9,16 @@ import com.uport.sdk.signer.encryption.KeyProtection import com.uport.sdk.signer.importHDSeed /** - * [Account] manager backed by a [UportHDSigner] that creates and uses key-pairs + * [HDAccount] manager backed by a [UportHDSigner] that creates and uses key-pairs * derived from a seed phrase. * * The seed is encrypted using AndroidKeyStore at rest */ -class KPAccountCreator(private val appContext: Context) : AccountCreator { +class HDAccountCreator(private val appContext: Context) : AccountCreator { val signer = UportHDSigner() - private suspend fun createOrImportAccount(networkId: String, phrase: String?): Account { + private suspend fun createOrImportAccount(networkId: String, phrase: String?): HDAccount { val (handle, _) = if (phrase.isNullOrBlank()) { signer.createHDSeed(appContext, KeyProtection.Level.SIMPLE) } else { @@ -29,23 +29,19 @@ class KPAccountCreator(private val appContext: Context) : AccountCreator { GENERIC_DEVICE_KEY_DERIVATION_PATH, "") - return Account( + return HDAccount( handle, deviceAddress, networkId, - deviceAddress, - "", - "", - "", - AccountType.KeyPair + deviceAddress ) } - override suspend fun createAccount(networkId: String, forceRecreate: Boolean): Account { + override suspend fun createAccount(networkId: String, forceRecreate: Boolean): HDAccount { return createOrImportAccount(networkId, null) } - override suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean): Account { + override suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean): HDAccount { return createOrImportAccount(networkId, seedPhrase) } diff --git a/identity/src/main/java/me/uport/sdk/identity/KeyPairAccount.kt b/identity/src/main/java/me/uport/sdk/identity/KeyPairAccount.kt new file mode 100644 index 00000000..926f41ca --- /dev/null +++ b/identity/src/main/java/me/uport/sdk/identity/KeyPairAccount.kt @@ -0,0 +1,48 @@ +package me.uport.sdk.identity + +import android.content.Context +import kotlinx.serialization.Transient +import me.uport.sdk.signer.KPSigner +import me.uport.sdk.signer.Signer + +/** + * This is an [Account] implementation that is backed by a KeyPair Signer. + * + * This account type does not support serialization + * + * This account type is still experimental and should only be used in test a environment + * + * API volatility: __high__ + */ + +data class KeyPairAccount( + + override val network: String, + + val signer: KPSigner + +) : Account { + + override val type: AccountType + get() = AccountType.KeyPair + + override val deviceAddress: String + get() = signer.getAddress() + + override val publicAddress: String + get() = signer.getAddress() + + override val handle: String + get() = signer.getAddress() + + @Transient + val address: String + get() = signer.getAddress() + + override fun getSigner(context: Context): Signer = signer + + /** + * This function generates and returns the DID associated with an account + */ + override fun getDID(): String = "did:ethr:$publicAddress" +} diff --git a/identity/src/main/java/me/uport/sdk/identity/KeyPairAccountCreator.kt b/identity/src/main/java/me/uport/sdk/identity/KeyPairAccountCreator.kt new file mode 100644 index 00000000..b2ebd5f8 --- /dev/null +++ b/identity/src/main/java/me/uport/sdk/identity/KeyPairAccountCreator.kt @@ -0,0 +1,35 @@ +package me.uport.sdk.identity + +import me.uport.sdk.signer.KPSigner + +/** + * [KeyPairAccountCreator] backed by a [KPSigner] that creates a [KeyPairAccount] + * + * This account creator is still experimental and should only be used in test a environment + * + * API volatility: __high__ + */ +class KeyPairAccountCreator(privateKey: String) : AccountCreator { + + private val signer = KPSigner(privateKey) + + private fun createOrImportAccount(networkId: String): KeyPairAccount { + + return KeyPairAccount( + networkId, + signer + ) + } + + override suspend fun createAccount(networkId: String, forceRecreate: Boolean): KeyPairAccount { + return createOrImportAccount(networkId) + } + + override suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean): KeyPairAccount { + return createOrImportAccount(networkId) + } + + override suspend fun deleteAccount(handle: String) { + //do nothing + } +} diff --git a/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccount.kt b/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccount.kt new file mode 100644 index 00000000..ad0bf5c6 --- /dev/null +++ b/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccount.kt @@ -0,0 +1,84 @@ +package me.uport.sdk.identity + +import android.content.Context +import android.support.annotation.VisibleForTesting +import com.uport.sdk.signer.UportHDSigner +import com.uport.sdk.signer.UportHDSignerImpl +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.json.Json +import me.uport.mnid.MNID +import me.uport.sdk.signer.Signer + + +/** + * This is an Account implementation for "MetaIdentityManager" account type. + */ +@Serializable +data class MetaIdentityAccount( + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + @SerialName("uportRoot") + override val handle: String, + + @SerialName("devKey") + override val deviceAddress: String, + + @SerialName("network") + override val network: String, + + @SerialName("proxy") + override val publicAddress: String, + + @SerialName("manager") + val identityManagerAddress: String, + + @SerialName("txRelay") + val txRelayAddress: String, + + @SerialName("fuelToken") + val fuelToken: String, + + @SerialName("signerType") + override val type: AccountType = AccountType.MetaIdentityManager + +) : Account { + + @Transient + val address: String + get() = getMnid() + + /** + * returns MNID for associated account + */ + fun getMnid() = MNID.encode(network, publicAddress) + + /** + * serializes account + */ + fun toJson(pretty: Boolean = false): String = if (pretty) Json.indented.stringify(MetaIdentityAccount.serializer(), this) else Json.stringify(MetaIdentityAccount.serializer(), this) + + override fun getSigner(context: Context): Signer = UportHDSignerImpl(context, UportHDSigner(), rootAddress = handle, deviceAddress = deviceAddress) + + /** + * This function generates and returns the DID associated with an account + */ + override fun getDID(): String = "did:uport:${getMnid()}" + + companion object { + + val blank = MetaIdentityAccount("", "", "", "", "", "", "") + + /** + * de-serializes account + */ + fun fromJson(serializedAccount: String?): MetaIdentityAccount? { + if (serializedAccount == null || serializedAccount.isEmpty()) { + return null + } + + return Json.nonstrict.parse(MetaIdentityAccount.serializer(), serializedAccount) + } + } +} \ No newline at end of file diff --git a/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccountCreator.kt b/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccountCreator.kt index cc1c6f29..fabca95f 100644 --- a/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccountCreator.kt +++ b/identity/src/main/java/me/uport/sdk/identity/MetaIdentityAccountCreator.kt @@ -1,3 +1,4 @@ +@file:Suppress("DEPRECATION") package me.uport.sdk.identity import android.content.Context @@ -18,14 +19,14 @@ import me.uport.sdk.identity.ProgressPersistence.PersistentBundle import me.uport.sdk.identity.endpoints.Unnu /** - * [Account] manager backed by a [UportHDSigner] that controls a + * [MetaIdentityAccount] manager backed by a [UportHDSigner] that controls a * [uPort proxy account](https://github.com/uport-project/uport-identity). * * This type of account supports meta-transactions but require fuel-tokens * - * **Work on this identity model is on hold and no support is available. Please use [KPAccountCreator]** + * **Work on this identity model is on hold and no support is available. Please use [HDAccountCreator]** */ -@Deprecated("Work on this identity model is on hold and no support is available. Please use [KPAccountCreator]") +@Deprecated("Work on this identity model is on hold and no support is available. Please use [HDAccountCreator]") class MetaIdentityAccountCreator( private val context: Context, private val fuelTokenProvider: IFuelTokenProvider) : AccountCreator { @@ -45,7 +46,7 @@ class MetaIdentityAccountCreator( * To force the creation of a new identity, use [forceRestart] */ @Suppress("LabeledExpression", "ComplexMethod") - private fun createOrImportAccount(networkId: String, phrase: String?, forceRestart: Boolean): Account = runBlocking { + private fun createOrImportAccount(networkId: String, phrase: String?, forceRestart: Boolean): MetaIdentityAccount = runBlocking { var (state, oldBundle) = if (forceRestart) { (AccountCreationState.NONE to PersistentBundle()) @@ -113,15 +114,14 @@ class MetaIdentityAccountCreator( if (identityInfo != Unnu.IdentityInfo.blank) { val proxyAddress = identityInfo.proxyAddress ?: "" - val acc = Account( + val acc = MetaIdentityAccount( oldBundle.rootAddress, oldBundle.deviceAddress, networkId, proxyAddress, identityInfo.managerAddress, Networks.get(networkId).txRelayAddress, - oldBundle.fuelToken, - AccountType.MetaIdentityManager + oldBundle.fuelToken ) state = AccountCreationState.COMPLETE progress.save(state, oldBundle.copy(partialAccount = acc)) @@ -148,11 +148,11 @@ class MetaIdentityAccountCreator( */ class AccountCreationError(state: AccountCreationState) : RuntimeException("Exhausted account creation options, ${state.name}") - override suspend fun createAccount(networkId: String, forceRecreate: Boolean): Account { + override suspend fun createAccount(networkId: String, forceRecreate: Boolean): MetaIdentityAccount { return createOrImportAccount(networkId, null, forceRecreate) } - override suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean): Account { + override suspend fun importAccount(networkId: String, seedPhrase: String, forceRecreate: Boolean): MetaIdentityAccount { return createOrImportAccount(networkId, seedPhrase, forceRecreate) } @@ -165,4 +165,4 @@ class MetaIdentityAccountCreator( private const val POLLING_INTERVAL = 5000L } -} \ No newline at end of file +} diff --git a/identity/src/main/java/me/uport/sdk/identity/ProgressPersistence.kt b/identity/src/main/java/me/uport/sdk/identity/ProgressPersistence.kt index a72f190e..46864151 100644 --- a/identity/src/main/java/me/uport/sdk/identity/ProgressPersistence.kt +++ b/identity/src/main/java/me/uport/sdk/identity/ProgressPersistence.kt @@ -49,13 +49,13 @@ class ProgressPersistence(context: Context) { val txHash: String = "", @SerialName("partialAccount") - val partialAccount: Account = Account.blank + val partialAccount: MetaIdentityAccount = MetaIdentityAccount.blank ) { - fun toJson() = Json.stringify(PersistentBundle.serializer(), this) + fun toJson() = Json.stringify(serializer(), this) companion object { fun fromJson(json: String): PersistentBundle = try { - Json.nonstrict.parse(PersistentBundle.serializer(), json) + Json.nonstrict.parse(serializer(), json) } catch (err: Exception) { PersistentBundle() } diff --git a/identity/src/main/java/me/uport/sdk/identity/endpoints/Unnu.kt b/identity/src/main/java/me/uport/sdk/identity/endpoints/Unnu.kt index 5f4ccb96..dc6b75f9 100644 --- a/identity/src/main/java/me/uport/sdk/identity/endpoints/Unnu.kt +++ b/identity/src/main/java/me/uport/sdk/identity/endpoints/Unnu.kt @@ -85,7 +85,7 @@ class Unnu(private val httpClient: HttpClient = HttpClient()) { /** * parses a JsonRPC response into an [IdentityInfoJRPCResponse] object */ - fun fromJson(json: String): IdentityInfoJRPCResponse = Json.nonstrict.parse(IdentityInfoJRPCResponse.serializer(), json) + fun fromJson(json: String): IdentityInfoJRPCResponse = Json.nonstrict.parse(serializer(), json) } } diff --git a/identity/src/test/java/me/uport/sdk/identity/AccountsTests.kt b/identity/src/test/java/me/uport/sdk/identity/AccountsTests.kt index 106de20c..b6a34001 100644 --- a/identity/src/test/java/me/uport/sdk/identity/AccountsTests.kt +++ b/identity/src/test/java/me/uport/sdk/identity/AccountsTests.kt @@ -1,7 +1,9 @@ package me.uport.sdk.identity -import assertk.assert -import assertk.assertions.* +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isNotNull +import assertk.assertions.isTrue import me.uport.sdk.core.Networks import me.uport.sdk.ethrdid.EthrDIDResolver import me.uport.sdk.jsonrpc.JsonRPC @@ -12,21 +14,18 @@ class AccountsTests { @Test fun `can serialize and deserialize account`() { - val refAccount = Account( + val refAccount = HDAccount( "0xroot", "0xdevice", "0x1", - "0xpublic", - "", - "", - "" + "0xpublic" ) val serialized = refAccount.toJson() - val other = Account.fromJson(serialized) + val other = HDAccount.fromJson(serialized) - assert(other).isEqualTo(refAccount) + assertThat(other).isEqualTo(refAccount) } @Test @@ -39,43 +38,39 @@ class AccountsTests { "devKey":"0xaddress", "network":"0x4", "proxy":"0xpublicaddress", - "manager":"0xidentityManagerAddress", - "txRelay":"0xtxRelayAddress", - "fuelToken":"base64FuelToken", - "signerType":"KeyPair" + "signerType":"HDKeyPair" }""".trimIndent() - val account = Account.fromJson(serializedAccount) + val account = HDAccount.fromJson(serializedAccount) - assert(account).isNotNull() - assert(account!!.isDefault!!).isFalse() + assertThat(account).isNotNull() } @Test - fun `validates did from keypair account`() { + fun `can deserialize deprecated account into hdaccount`() { + //language=JSON val serializedAccount = """ { - "uportRoot": "0x1f9339e3c08c120b4ee05d2f500d57000170664d", - "devKey": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", - "network": "0x04", - "proxy": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", - "manager": "", - "txRelay": "", - "fuelToken": "", - "signerType": "KeyPair", - "isDefault": true + "uportRoot":"0xrootAddress", + "devKey":"0xaddress", + "network":"0x4", + "proxy":"0xpublicaddress", + "manager":"0xidentityManagerAddress", + "txRelay":"0xtxRelayAddress", + "fuelToken":"base64FuelToken", + "signerType":"KeyPair" }""".trimIndent() - val account = Account.fromJson(serializedAccount) - val defaultRPC = JsonRPC(Networks.mainnet.rpcUrl) - val canResolve = EthrDIDResolver(defaultRPC).canResolve(account!!.getDID()) - assert(canResolve) + val account = HDAccount.fromJson(serializedAccount) + + assertThat(account).isNotNull() } @Test - fun `validates did from meta identity account`() { + fun `can deserialize deprecated account into meta identity account`() { + //language=JSON val serializedAccount = """ { "uportRoot":"0xrootAddress", @@ -88,13 +83,31 @@ class AccountsTests { "signerType":"MetaIdentityManager" }""".trimIndent() - val account = Account.fromJson(serializedAccount) - val tested = UportDIDResolver(JsonRPC(Networks.rinkeby.rpcUrl)) - assert(tested.canResolve(account!!.getDID())).isTrue() + val account = MetaIdentityAccount.fromJson(serializedAccount) + + assertThat(account).isNotNull() + } + + @Test + fun `validates did from keypair account`() { + + val serializedAccount = """ + { + "uportRoot": "0x1f9339e3c08c120b4ee05d2f500d57000170664d", + "devKey": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", + "network": "0x04", + "proxy": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", + "signerType": "HDKeyPair", + }""".trimIndent() + + val account = HDAccount.fromJson(serializedAccount) + val defaultRPC = JsonRPC(Networks.mainnet.rpcUrl) + val canResolve = EthrDIDResolver(defaultRPC).canResolve(account!!.getDID()) + assertThat(canResolve) } @Test - fun `throws error for invalid account type`() { + fun `validates did from meta identity account`() { val serializedAccount = """ { @@ -105,16 +118,11 @@ class AccountsTests { "manager":"0xidentityManagerAddress", "txRelay":"0xtxRelayAddress", "fuelToken":"base64FuelToken", - "signerType":"Proxy" + "signerType":"MetaIdentityManager" }""".trimIndent() - val account = Account.fromJson(serializedAccount) - assert { - account!!.getDID() - }.thrownError { - isInstanceOf(IllegalStateException::class) - } + val account = MetaIdentityAccount.fromJson(serializedAccount) + val tested = UportDIDResolver(JsonRPC(Networks.rinkeby.rpcUrl)) + assertThat(tested.canResolve(account!!.getDID())).isTrue() } - - } diff --git a/identity/src/test/java/me/uport/sdk/identity/KeyPairAccountCreatorTest.kt b/identity/src/test/java/me/uport/sdk/identity/KeyPairAccountCreatorTest.kt new file mode 100644 index 00000000..c5784b88 --- /dev/null +++ b/identity/src/test/java/me/uport/sdk/identity/KeyPairAccountCreatorTest.kt @@ -0,0 +1,29 @@ +package me.uport.sdk.identity + +import assertk.all +import assertk.assertThat +import assertk.assertions.isNotEmpty +import assertk.assertions.isNotEqualTo +import assertk.assertions.isNotNull +import kotlinx.coroutines.runBlocking +import me.uport.sdk.core.Networks +import org.junit.Test + +class KeyPairAccountCreatorTest { + + @Test + fun createAccount() { + runBlocking { + val account = KeyPairAccountCreator("0x1234").createAccount(Networks.rinkeby.networkId) + + assertThat(account).all { + isNotNull() + isNotEqualTo(HDAccount.blank) + } + + assertThat(account.address).isNotEmpty() + assertThat(account.publicAddress).isNotEmpty() + assertThat(account.deviceAddress).isNotEmpty() + } + } +} \ No newline at end of file diff --git a/jsonrpc/build.gradle b/jsonrpc/build.gradle deleted file mode 100644 index 1d6d29f1..00000000 --- a/jsonrpc/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -apply plugin: "com.android.library" -apply plugin: "kotlin-android" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "wrappers for calling ethereum endpoints using json-rpc" - -android { - compileSdkVersion compile_sdk_version - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" - implementation "com.android.support:support-annotations:$support_lib_version" - implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" - - api "com.github.walleth.kethereum:model:$kethereum_version" - api "com.github.walleth.kethereum:rlp:$kethereum_version" - api "com.github.walleth.kethereum:functions:$kethereum_version" - - api project(":core") - - testImplementation "junit:junit:$junit_version" - testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" - testImplementation "io.mockk:mockk:$mockk_version" -} \ No newline at end of file diff --git a/jsonrpc/src/main/AndroidManifest.xml b/jsonrpc/src/main/AndroidManifest.xml deleted file mode 100644 index acc3912b..00000000 --- a/jsonrpc/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPC.kt b/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPC.kt deleted file mode 100644 index 2b417731..00000000 --- a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPC.kt +++ /dev/null @@ -1,349 +0,0 @@ -@file:Suppress("LiftReturnOrAssignment", "UnnecessaryVariable") - -package me.uport.sdk.jsonrpc - -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PRIVATE -import com.squareup.moshi.Json -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import me.uport.sdk.core.HttpClient -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.extensions.toHexStringNoPrefix -import org.walleth.khex.prepend0xPrefix -import java.io.IOException -import java.lang.reflect.ParameterizedType -import java.math.BigInteger - -/** - * Partial wrapper for JsonRPC methods supported by ethereum nodes. - */ -open class JsonRPC(private val rpcEndpoint: String, val httpClient: HttpClient = HttpClient()) { - -//============================= -// eth_call -//============================= - - /** - * performs an eth_call - * the `result` of the JsonRPC call is returned as String. - * Known parsing errors are caught and rethrown, network errors are bubbled up. - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call - * - * @throws JsonRpcException for error replies coming from the endpoint - * @throws IOException for network errors or unexpected reply formats - */ - open suspend fun ethCall(address: String, data: String): String { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_call", - params = listOf( - mapOf("to" to address, - "data" to data), - "latest") - ).toJson() - - return jsonRpcGenericCall(rpcEndpoint, payloadRequest) - } - - -//============================= -// eth_getLogs -//============================= - - /** - * obtains the list of [JsonRpcLogItem]s corresponding to a given [address] and [topics] between [[fromBlock]..[toBlock]] - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs - * - * @throws JsonRpcException for error replies coming from the endpoint - * @throws IOException for network errors or unexpected reply formats - */ - suspend fun getLogs(address: String, topics: List = emptyList(), fromBlock: BigInteger, toBlock: BigInteger): List { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_getLogs", - params = listOf( - mapOf( - "fromBlock" to fromBlock.toHexStringNoPrefix().prepend0xPrefix(), - "toBlock" to toBlock.toHexStringNoPrefix().prepend0xPrefix(), - "address" to address, - "topics" to topics - ) - ) - ).toJson() - - val logItemsRaw = jsonRpcGenericCall(rpcEndpoint, payloadRequest) - val type: ParameterizedType = Types.newParameterizedType(List::class.java, JsonRpcLogItem::class.java) - val jsonAdapter: JsonAdapter> = moshi.adapter(type) - val logs = jsonAdapter.lenient().fromJson(logItemsRaw) ?: emptyList() - return logs - - } - -//============================= -// eth_gasPrice -//============================= - - /** - * Obtains the gas price in Wei or throws an error if one occurred - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gasPrice - */ - suspend fun getGasPrice(): BigInteger { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_gasPrice", - params = emptyList() - ).toJson() - - val priceHex = jsonRpcGenericCall(rpcEndpoint, payloadRequest) - return priceHex.hexToBigInteger() - } - - -//============================= -//eth_getTransactionCount -//============================= - - /** - * Calls back with the number of already mined transactions made from the given address. - * The number is usable as `nonce` (since nonce is zero indexed) - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getTransactionCount - * - * FIXME: account for pending transactions - */ - suspend fun getTransactionCount(address: String): BigInteger { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_getTransactionCount", - params = listOf(address, "latest") - ).toJson() - - val nonceHex = jsonRpcGenericCall(rpcEndpoint, payloadRequest) - return nonceHex.hexToBigInteger() - } - - -//============================= -//eth_getBalance -//============================= - - /** - * Calls back with the ETH balance of an account (expressed in Wei) - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getBalance - */ - suspend fun getAccountBalance(address: String): BigInteger { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_getBalance", - params = listOf(address, "latest") - ).toJson() - - val weiCountHex = jsonRpcGenericCall(rpcEndpoint, payloadRequest) - return weiCountHex.hexToBigInteger() - } - - -//============================= -// eth_getTransactionReceipt -//============================= - - /** - * Wrapper for a transaction receipt response - */ - class JsonRpcReceiptResponse(override val result: TransactionReceipt?) : JsonRpcBaseResponse() { - - companion object { - private val adapter by lazy { - moshi.adapter(JsonRpcReceiptResponse::class.java) - } - - fun fromJson(json: String) = adapter.fromJson(json) - } - } - - /** - * Data representing a Transaction receipt - */ - data class TransactionReceipt( - - @Json(name = "transactionHash") - val transactionHash: String? = "", - - @Json(name = "transactionIndex") - val transactionIndex: String? = "", - - @Json(name = "blockNumber") - val blockNumber: String? = "", - - @Json(name = "blockHash") - val blockHash: String? = "", - - @Json(name = "cumulativeGasUsed") - val cumulativeGasUsed: String? = "", - - @Json(name = "contractAddress") - val contractAddress: String? = null, - - @Json(name = "logs") - val logs: List? = null, - - @Json(name = "logsBloom") - val logsBloom: String? = "", - - @Json(name = "status") - val status: String? = "0x0" - ) - - /** - * Obtains a transaction receipt for a given [txHash] - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getTransactionReceipt - */ - suspend fun getTransactionReceipt(txHash: String): TransactionReceipt { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_getTransactionReceipt", - params = arrayListOf(txHash) - ).toJson() - - val rawResult = httpClient.urlPost(rpcEndpoint, payloadRequest) - val parsedResponse = JsonRpcReceiptResponse.fromJson(rawResult) - ?: throw IOException("RPC endpoint response for transaction receipt query cannot be parsed") - if (parsedResponse.error != null) { - throw parsedResponse.error.toException() - } - - if (parsedResponse.result != null) { - return parsedResponse.result - } else { - throw TransactionNotFoundException(txHash) - } - } - - -//============================= -// eth_getTransactionByHash -//============================= - - /** - * wrapper for transaction information responses - */ - class JsonRpcTxByHashResponse(override val result: TransactionInformation?) : JsonRpcBaseResponse() { - - companion object { - private val adapter by lazy { - moshi.adapter(JsonRpcTxByHashResponse::class.java) - } - - fun fromJson(json: String) = adapter.fromJson(json) - } - } - - /** - * Obtains the transaction information corresponding to a given [txHash] - * - * See also: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getTransactionByHash - */ - suspend fun getTransactionByHash(txHash: String): TransactionInformation { - val payloadRequest = JsonRpcBaseRequest( - method = "eth_getTransactionByHash", - params = arrayListOf(txHash) - ).toJson() - - val rawResult = httpClient.urlPost(rpcEndpoint, payloadRequest) - val parsedResponse = JsonRpcTxByHashResponse.fromJson(rawResult) - ?: throw IOException("RPC endpoint response for transaction information query cannot be parsed") - if (parsedResponse.error != null) { - throw parsedResponse.error.toException() - } - - if (parsedResponse.result != null) { - return parsedResponse.result - } else { - throw TransactionNotFoundException(txHash) - } - } - - /** - * Data representing the transaction information - */ - data class TransactionInformation( - @Json(name = "hash") - val txHash: String? = null, - - @Json(name = "nonce") - val nonce: String? = null, - - @Json(name = "blockHash") - val blockHash: String? = null, - - @Json(name = "blockNumber") - val blockNumber: String? = null, - - @Json(name = "transactionIndex") - val transactionIndex: String? = null, - - @Json(name = "from") - val from: String = "", - - @Json(name = "to") - val to: String = "", - - @Json(name = "value") - val value: String = "", - - @Json(name = "gas") - val gas: String = "", - - @Json(name = "gasPrice") - val gasPrice: String = "", - - @Json(name = "input") - val input: String = "" - ) - - -//============================= -//eth_sendRawTransaction -//============================= - - /** - * Sends a hex string representing a [signedTransactionHex] to be mined by the ETH network. - * - * @return the txHash of the transaction if it is accepted by the JsonRPC node. - * - * @throws JsonRpcException for error replies coming from the [rpcEndpoint] - * @throws IOException for network errors or unexpected reply formats - */ - suspend fun sendRawTransaction( - signedTransactionHex: String - ): String { - - val payloadRequest = JsonRpcBaseRequest( - method = "eth_sendRawTransaction", - params = listOf(signedTransactionHex) - ).toJson() - - return jsonRpcGenericCall(rpcEndpoint, payloadRequest) - } - - /** - * Make a base JsonRPCRequest to the [url] with the given [payloadRequest] - * and attempt to parse the response string into a [JsonRpcBaseResponse] - * @throws IOException if response is null or if it can't be parsed from JSON - * @throws JsonRpcException if the response was parsed and an error field was present - */ - @VisibleForTesting(otherwise = PRIVATE) - suspend fun jsonRpcGenericCall(url: String, payloadRequest: String): String { - val rawResult = httpClient.urlPost(url, payloadRequest) - val parsedResponse = JsonRpcBaseResponse.fromJson(rawResult) - ?: throw IOException("RPC endpoint response can't be parsed as JSON") - parsedResponse.error?.let { - throw it.toException() - } - return parsedResponse.result.toString() - } - -} - - - diff --git a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPCBase.kt b/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPCBase.kt deleted file mode 100644 index 16ca2ff3..00000000 --- a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/JsonRPCBase.kt +++ /dev/null @@ -1,122 +0,0 @@ -package me.uport.sdk.jsonrpc - -import android.support.annotation.Keep -import com.squareup.moshi.FromJson -import com.squareup.moshi.Json -import com.squareup.moshi.Moshi -import com.squareup.moshi.ToJson -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -import org.kethereum.extensions.maybeHexToBigInteger -import org.kethereum.extensions.toHexStringNoPrefix -import org.walleth.khex.prepend0xPrefix -import java.math.BigInteger - - -/** - * Data class that encapsulates a basic JsonRPC request - */ -@Keep -open class JsonRpcBaseRequest( - @Json(name = "method") - val method: String, - - @Json(name = "params") - val params: Collection, - - @Json(name = "id") - val id: Int = 1, - - @Json(name = "jsonrpc") - val jsonrpc: String = "2.0") { - - /** - * serializer for this [JsonRpcBaseRequest] - */ - fun toJson(): String = jsonAdapter.toJson(this) ?: "" - - companion object { - private val jsonAdapter = moshi.adapter(JsonRpcBaseRequest::class.java) - } -} - -/** - * Data class that encapsulates a generic JsonRPC response - */ -@Keep -open class JsonRpcBaseResponse( - @Json(name = "result") - open val result: Any? = null, - - @Json(name = "error") - val error: JsonRpcError? = null, - - @Json(name = "id") - val id: Int = 1, - - @Json(name = "jsonrpc") - val jsonrpc: String = "2.0") { - - companion object { - - /** - * Deserializer for [JsonRpcBaseResponse] - */ - fun fromJson(json: String): JsonRpcBaseResponse? = jsonAdapter?.fromJson(json) - - private val jsonAdapter = moshi.adapter(JsonRpcBaseResponse::class.java) - } -} - -/** - * Class that represents an error returned by a JsonRPC endpoint - */ -class JsonRpcError(val code: Int, val message: String) { - /** - * Convert this to an [JsonRpcException] so it can be thrown - */ - fun toException() = JsonRpcException(code, message) -} - -/** - * Exception equivalent of a [JsonRpcError] - */ -class JsonRpcException( - val code: Int = -32603, - override val message: String = "Internal error" -) : Exception(message) - -/** - * Data class that encapsulates a log item for eth_getLogs - */ -data class JsonRpcLogItem( - val address: String, - val topics: List, - val data: String, - val blockNumber: BigInteger, - val transactionHash: String, - val transactionIndex: BigInteger, - val blockHash: String, - val logIndex: BigInteger, - val removed: Boolean - -) - -/** - * Helper class to convert between hex strings and [BigInteger] in JSON (de)serialization - */ -class JsonRPCSerializers { - @FromJson - fun fromJson(hexString: String): BigInteger = hexString.maybeHexToBigInteger() - - @ToJson - fun toJson(number: BigInteger): String = number.toHexStringNoPrefix().prepend0xPrefix() -} - -/** - * global used to hook into JSON (de)serialization - */ -val moshi: Moshi = Moshi.Builder() - .add(JsonRPCSerializers()) - .add(KotlinJsonAdapterFactory()) - .build() - diff --git a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/TransactionNotFoundException.kt b/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/TransactionNotFoundException.kt deleted file mode 100644 index 6db24348..00000000 --- a/jsonrpc/src/main/java/me/uport/sdk/jsonrpc/TransactionNotFoundException.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.uport.sdk.jsonrpc - -/** - * Thrown when a `txHash` is not known by the ETH network - */ -class TransactionNotFoundException(txHash: String) : RuntimeException("The transaction with hash=$txHash has not been mined yet") \ No newline at end of file diff --git a/jsonrpc/src/test/java/me/uport/sdk/jsonrpc/JsonRpcBaseResponseTest.kt b/jsonrpc/src/test/java/me/uport/sdk/jsonrpc/JsonRpcBaseResponseTest.kt deleted file mode 100644 index 80501e14..00000000 --- a/jsonrpc/src/test/java/me/uport/sdk/jsonrpc/JsonRpcBaseResponseTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -package me.uport.sdk.jsonrpc - -import assertk.assert -import assertk.assertions.isEqualTo -import assertk.assertions.isNotNull -import io.mockk.coEvery -import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import me.uport.sdk.core.HttpClient -import me.uport.sdk.core.Networks -import org.junit.Test -import java.math.BigInteger - -class JsonRpcBaseResponseTest { - - //language=JSON - private val logItemJson = """ -{ - "address":"0xdca7ef03e98e0dc2b855be647c39abe984fcf21b", - "topics": [ - "0x38a5a6e68f30ed1ab45860a4afb34bcb2fc00f22ca462d249b8a8d40cda6f7a3", - "0x000000000000000000000000f3beac30c498d9e26865f34fcaa57dbb935b0d74" - ], - "data": "0x00000000000000000000000045c4ebd7ffb86891ba6f9f68452f9f0815aacd8b0000000000000000000000000000000000000000000000000000000000000000", - "blockNumber":"0x29db37", - "transactionHash":"0x70829b62ac232269a0524b180054532eff18b5fbc60b7102b6120844b5cdb1d8", - "transactionIndex":"0x1", - "blockHash":"0xf0bfb1aaa47ce10e6aa99940bafc2bb11f3de742d44d2288b4546250e67b0971", - "logIndex":"0x0", - "removed":false -} -""".trimIndent() - - @Test - fun `can deserialize log item json`() { - val adapter = moshi.adapter(JsonRpcLogItem::class.java) - val item = adapter.fromJson(logItemJson) - - - assert(item).isNotNull() - item!! - - assert(item.address).isEqualTo("0xdca7ef03e98e0dc2b855be647c39abe984fcf21b") - assert(item.topics.size).isEqualTo(2) - assert(item.transactionIndex).isEqualTo(BigInteger.ONE) - } - - @Test - fun `can parse transaction receipt`() = runBlocking { - val http = mockk { - //language=json - coEvery { urlPost(any(), any()) } returns """{"jsonrpc":"2.0","id":1,"result":{"blockHash":"0x5619e5036d2288fbda3298be5d9003f2622993465945ad4d25377dd9f6c15646","blockNumber":"0x38ecec","contractAddress":null,"cumulativeGasUsed":"0x14510c","from":"0xbe1085bc3e0812f3df63deced87e29b3bc2db524","gasUsed":"0x1230f","logs":[{"address":"0x40af244c94e679aebf897512720a41d843954a29","blockHash":"0x5619e5036d2288fbda3298be5d9003f2622993465945ad4d25377dd9f6c15646","blockNumber":"0x38ecec","data":"0x00000000000000000000000000000000000000000000000000000000549adbf85915ab705f44b3c43ecc0c2d34834a863132cc200c23016acd57d47b8aa8cf0d000000000000000000000000000000000000000000000000000000005c45f692","logIndex":"0xa","removed":false,"topics":["0x6d91cd6ccac8368394df514e6aee19a55264f5ab49a891af91ca86da27bedd4f"],"transactionHash":"0x1dab51a1127c0294359193b1e0b7f2c8e414efe7e9a85dee59fca21d9b179dcb","transactionIndex":"0x7"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000080000000000","status":"0x1","to":"0x40af244c94e679aebf897512720a41d843954a29","transactionHash":"0x1dab51a1127c0294359193b1e0b7f2c8e414efe7e9a85dee59fca21d9b179dcb","transactionIndex":"0x7"}}""" - } - - val tested = JsonRPC(Networks.rinkeby.rpcUrl, http) - - val receipt = tested.getTransactionReceipt("0x1dab51a1127c0294359193b1e0b7f2c8e414efe7e9a85dee59fca21d9b179dcb") - assert(receipt).isNotNull() - } -} \ No newline at end of file diff --git a/jwt/build.gradle b/jwt/build.gradle deleted file mode 100644 index 0b6ecacc..00000000 --- a/jwt/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -apply plugin: "com.android.library" -apply plugin: "kotlin-android" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "tools for creating and verifying JWTs that use uPort algorithms" - -android { - compileSdkVersion compile_sdk_version - buildToolsVersion build_tools_version - - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - multiDexEnabled = true - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "com.android.support:support-annotations:$support_lib_version" - api "com.github.walleth.kethereum:model:$kethereum_version" - api "com.github.walleth.kethereum:crypto:$kethereum_version" - api "com.github.walleth.kethereum:extensions:$kethereum_version" - - api project(":signer") - api project(":uport-did") - api project(":ethr-did") - api project(":https-did") - api project(":jsonrpc") - api project(":core") - api project(":serialization") - - testImplementation "junit:junit:$junit_version" - testImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" - testImplementation project(":test-helpers") - testImplementation "io.mockk:mockk:$mockk_version" - - androidTestImplementation "com.willowtreeapps.assertk:assertk-jvm:$assertk_version" - androidTestImplementation "com.android.support.test:runner:$test_runner_version" - androidTestImplementation "io.mockk:mockk-android:$mockk_version" - androidTestImplementation project(":test-helpers") -} \ No newline at end of file diff --git a/jwt/proguard-rules.pro b/jwt/proguard-rules.pro deleted file mode 100644 index f1b42451..00000000 --- a/jwt/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTSignerAlgorithmRuntimeTest.kt b/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTSignerAlgorithmRuntimeTest.kt deleted file mode 100644 index 12afd2ea..00000000 --- a/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTSignerAlgorithmRuntimeTest.kt +++ /dev/null @@ -1,64 +0,0 @@ -package me.uport.sdk.jwt - -import android.support.test.InstrumentationRegistry -import assertk.assert -import assertk.assertions.isEqualTo -import com.uport.sdk.signer.UportHDSigner -import com.uport.sdk.signer.UportHDSignerImpl -import kotlinx.coroutines.runBlocking -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K_R -import org.junit.Before -import org.junit.Test - -class JWTSignerAlgorithmRuntimeTest { - - private val referenceSeed = "vessel ladder alter error federal sibling chat ability sun glass valve picture" - private var appContext = InstrumentationRegistry.getTargetContext() - private lateinit var rootAddress: String - - @Before - fun run_before_every_test() { - val (handle, _) = runBlocking { ensureSeedIsImported(appContext, referenceSeed) } - rootAddress = handle - } - - @Test - fun can_sign_using_non_recoverable_alg() = runBlocking { - - val referencePayload = "Hello, world!" - - val testedSigner = UportHDSignerImpl( - context = appContext, - uportHDSigner = UportHDSigner(), - rootAddress = rootAddress, - deviceAddress = rootAddress - ) - - val signature = JWTSignerAlgorithm(ES256K).sign(referencePayload, testedSigner) - - val expectedSignature = "a82BRGGDrxk8pKFy1cXCY0WQOyR3DZC115D3Sp3sH2jiuFs8ksm0889Y3kbnmX2O-24UsuUy0T36Iu4C86Q9XQ" - assert(signature).isEqualTo(expectedSignature) - assert(signature.decodeBase64().size).isEqualTo(64) - } - - @Test - fun can_sign_using_recoverable_alg() = runBlocking { - - val referencePayload = "Hello, world!" - - val testedSigner = UportHDSignerImpl( - context = appContext, - uportHDSigner = UportHDSigner(), - rootAddress = rootAddress, - deviceAddress = rootAddress - ) - - val signature = JWTSignerAlgorithm(ES256K_R).sign(referencePayload, testedSigner) - - val expectedSignature = "a82BRGGDrxk8pKFy1cXCY0WQOyR3DZC115D3Sp3sH2jiuFs8ksm0889Y3kbnmX2O-24UsuUy0T36Iu4C86Q9XQE" - assert(signature).isEqualTo(expectedSignature) - assert(signature.decodeBase64().size).isEqualTo(65) - } -} \ No newline at end of file diff --git a/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTToolsTests.kt b/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTToolsTests.kt deleted file mode 100644 index deece53e..00000000 --- a/jwt/src/androidTest/java/me/uport/sdk/jwt/JWTToolsTests.kt +++ /dev/null @@ -1,107 +0,0 @@ -package me.uport.sdk.jwt - -/** - * Created by aldi on 3/10/18. - */ -import android.content.Context -import android.support.test.InstrumentationRegistry -import assertk.assert -import assertk.assertions.isEqualTo -import assertk.assertions.isNull -import com.uport.sdk.signer.UportHDSigner -import com.uport.sdk.signer.UportHDSignerImpl -import io.mockk.coEvery -import io.mockk.mockk -import io.mockk.spyk -import kotlinx.coroutines.runBlocking -import me.uport.sdk.jsonrpc.JsonRPC -import me.uport.sdk.jwt.model.JwtPayload -import me.uport.sdk.testhelpers.TestTimeProvider -import me.uport.sdk.universaldid.UniversalDID -import me.uport.sdk.uportdid.UportDIDDocument -import me.uport.sdk.uportdid.UportDIDResolver -import org.junit.Before -import org.junit.Test -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class JWTToolsTests { - - private val referenceSeedPhrase = "notice suffer eagle style exclude burst write mechanic junior crater crystal seek" - - private lateinit var appContext: Context - private lateinit var rootHandle: String - - @Before - fun run_before_every_test() { - appContext = InstrumentationRegistry.getTargetContext() - val (handle, _) = runBlocking { ensureSeedIsImported(appContext, referenceSeedPhrase) } - rootHandle = handle - } - - @Test - fun can_create_token_with_typed_payload() { - val rpc = mockk() - val resolver = spyk(UportDIDResolver(rpc)) { - coEvery { resolve(eq("2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH")) }.returns( - UportDIDDocument.fromJson("""{"id":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH","publicKey":[{"id":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH#keys-1","type":"Secp256k1VerificationKey2018","owner":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH","publicKeyHex":"0437c6a2555984b5a2c3a8947b0bd623eea1cfa3c13264b32345ffd771896d48395976849aaeb97460119f8b8965e04404d579662cd742f3438f74f0844c7c419c"},{"id":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH#keys-2","type":"Curve25519EncryptionPublicKey","owner":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH","publicKeyBase64":"LVfRrP9BVRkfglZueCpNLz5yCC6s583lQtneykGFrzU="}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:uport:2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH#keys-1"}],"service":[],"@context":"https://w3id.org/did/v1","uportProfile":{"@type":"Person"}}""") - ) - } - UniversalDID.registerResolver(resolver) - - val payload = JwtPayload(iss = "2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH", - aud = "2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG", - type = "shareResp", - nad = "2oufEA35y7GiApcdyL87Lp5zTV7NRNCF6HH", - own = mapOf( - "name" to "Identity 1", - "phone" to "10000", - "country" to "" - ), - req = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiIyb2VYdWZIR0RwVTUxYmZLQnNaRGR1N0plOXdlSjNyN3NWRyIsImlhdCI6MTUyMjEwMDM4OCwicmVxdWVzdGVkIjpbIm5hbWUiLCJwaG9uZSIsImNvdW50cnkiLCJhdmF0YXIiXSwicGVybWlzc2lvbnMiOlsibm90aWZpY2F0aW9ucyJdLCJjYWxsYmFjayI6Imh0dHBzOi8vZGVtby51cG9ydC5tZS8jIiwibmV0IjoiMHg0IiwiZXhwIjoxNTIyMTAwOTg4LCJ0eXBlIjoic2hhcmVSZXEifQ.3Lkbz4zG0kcDaOkhThFY9iGhvqagKmXHos15JHGl3IvSn6-fXJJTf6xsYCL_wYDHI3GctbNUHhTuCYkJRF5NPw", - capabilities = listOf("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiIyb3VmRUEzNXk3R2lBcGNkeUw4N0xwNXpUVjdOUk5DRjZISCIsImlhdCI6MTUyMjEwMDM5NiwiYXVkIjoiMm9lWHVmSEdEcFU1MWJmS0JzWkRkdTdKZTl3ZUozcjdzVkciLCJ0eXBlIjoibm90aWZpY2F0aW9ucyIsInZhbHVlIjoiYXJuOmF3czpzbnM6dXMtd2VzdC0yOjExMzE5NjIxNjU1ODplbmRwb2ludC9HQ00vdVBvcnQvMTkxZTBiMjctZWFmZi0zMWVkLTk4NGUtNTg2ZjU1OWYzMDEyIiwiZXhwIjoxNTIzMzk2Mzk2fQ.XyjR2iM0ZUgvolEhcP9n50g7JAJ9VMjS5_ASqj29-riOV1sEnYiLcH44E2joPo-clcFoA0owW19OcyRLpur50g") - ) - - val latch = CountDownLatch(1) - - //XXX: even though it's deprecated, it doesn't hurt to keep this test around until it's completely removed - @Suppress("DEPRECATION") - JWTTools().create(context = appContext, payload = payload, rootHandle = rootHandle, derivationPath = UportHDSigner.UPORT_ROOT_DERIVATION_PATH, prompt = "", callback = { err, newJwt -> - - assert(err).isNull() - - val verifiedPayload = runBlocking { JWTTools().verify(newJwt) } - assert(verifiedPayload).isEqualTo(payload) - - latch.countDown() - - }) - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun can_create_token_from_map_payload() = runBlocking { - val timeProvider = TestTimeProvider(12345678000L) - val tested = JWTTools(timeProvider) - - val payload = mapOf( - "claims" to mapOf("name" to "R Daneel Olivaw") - ) - val signer = UportHDSignerImpl( - appContext, - UportHDSigner(), - rootHandle, - rootHandle - ) - val issuerDID = "did:ethr:${signer.getAddress()}" - - val jwt = tested.createJWT(payload, issuerDID, signer) - val expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbXMiOnsibmFtZSI6IlIgRGFuZWVsIE9saXZhdyJ9LCJpYXQiOjEyMzQ1Njc4LCJleHAiOjEyMzQ1OTc4LCJpc3MiOiJkaWQ6ZXRocjoweDQxMjNjYmQxNDNiNTVjMDZlNDUxZmYyNTNhZjA5Mjg2YjY4N2E5NTAifQ.o6eDKYjHJnak1ylkpe9g8krxvK9UEhKf-1T0EYhH8pGyb8MjOEepRJi8DYlVEnZno0DkVYXQCf3u1i_HThBKtAA" - assert(jwt).isEqualTo(expected) - val (_, decodedPayload, _) = tested.decode(expected) - assert(decodedPayload.iat).isEqualTo(12345678L) - } - -} - - diff --git a/jwt/src/androidTest/java/me/uport/sdk/jwt/Utils.kt b/jwt/src/androidTest/java/me/uport/sdk/jwt/Utils.kt deleted file mode 100644 index e0fd8a8e..00000000 --- a/jwt/src/androidTest/java/me/uport/sdk/jwt/Utils.kt +++ /dev/null @@ -1,12 +0,0 @@ -package me.uport.sdk.jwt - -import android.content.Context -import com.uport.sdk.signer.UportHDSigner -import com.uport.sdk.signer.encryption.KeyProtection -import com.uport.sdk.signer.importHDSeed -import kotlinx.coroutines.runBlocking - -fun ensureSeedIsImported(appContext: Context, phrase: String) = runBlocking { - //ensure seed is imported - UportHDSigner().importHDSeed(appContext, KeyProtection.Level.SIMPLE, phrase) -} \ No newline at end of file diff --git a/jwt/src/main/AndroidManifest.xml b/jwt/src/main/AndroidManifest.xml deleted file mode 100644 index 7134563d..00000000 --- a/jwt/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/jwt/src/main/java/me/uport/sdk/jwt/ECUtils.kt b/jwt/src/main/java/me/uport/sdk/jwt/ECUtils.kt deleted file mode 100644 index 59722ad3..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/ECUtils.kt +++ /dev/null @@ -1,148 +0,0 @@ -package me.uport.sdk.jwt - -import com.uport.sdk.signer.getUncompressedPublicKeyWithPrefix -import org.kethereum.crypto.CURVE -import org.kethereum.crypto.model.PublicKey -import org.kethereum.hashes.sha256 -import org.kethereum.model.SignatureData -import org.spongycastle.asn1.x9.X9IntegerConverter -import org.spongycastle.crypto.digests.SHA256Digest -import org.spongycastle.crypto.params.ECDomainParameters -import org.spongycastle.crypto.params.ECPublicKeyParameters -import org.spongycastle.crypto.signers.ECDSASigner -import org.spongycastle.crypto.signers.HMacDSAKCalculator -import org.spongycastle.math.ec.ECAlgorithms -import org.spongycastle.math.ec.ECPoint -import org.spongycastle.math.ec.custom.sec.SecP256K1Curve -import java.math.BigInteger -import java.security.SignatureException - -private val DOMAIN_PARAMS = CURVE.run { ECDomainParameters(curve, g, n, h) } - -internal data class ECDSASignature internal constructor(val r: BigInteger, val s: BigInteger) - -/** - * This method matches the [messageHash] and its [signature] against a given [publicKey] - * on the secp256k1 elliptic curve - * - * @param messageHash The hash of the message. For JWT this is `sha256`, for ETH this is `keccak` - * @param signature the components of the signature. Only `r` and `s` are used for verification, the `v` component is ignored - * @param publicKey the public key to check against. - * - * @return `true` when there is a match or `false` otherwise - */ -internal fun ecVerify(messageHash: ByteArray, signature: SignatureData, publicKey: PublicKey): Boolean { - val publicKeyBytes = publicKey.getUncompressedPublicKeyWithPrefix() - - val ecPoint = CURVE.curve.decodePoint(publicKeyBytes) - - val verifier = ECDSASigner(HMacDSAKCalculator(SHA256Digest())) - - val ecPubKeyParams = ECPublicKeyParameters(ecPoint, DOMAIN_PARAMS) - verifier.init(false, ecPubKeyParams) - - return verifier.verifySignature(messageHash, signature.r, signature.s) -} - -/*** - * Copied from Kethereum because it is a private method there - */ -internal fun recoverFromSignature(recId: Int, sig: ECDSASignature, messageHash: ByteArray?): BigInteger? { - require(recId >= 0) { "recId must be positive" } - require(sig.r.signum() >= 0) { "r must be positive" } - require(sig.s.signum() >= 0) { "s must be positive" } - require(messageHash != null) { "message cannot be null" } - - // 1.0 For j from 0 to h (h == recId here and the loop is outside this function) - // 1.1 Let x = r + jn - val n = CURVE.n // Curve order. - val i = BigInteger.valueOf(recId.toLong() / 2) - val x = sig.r.add(i.multiply(n)) - // 1.2. Convert the integer x to an octet string X of length mlen using the conversion - // routine specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. - // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R - // using the conversion routine specified in Section 2.3.4. If this conversion - // routine outputs “invalid”, then do another iteration of Step 1. - // - // More concisely, what these points mean is to use X as a compressed public key. - val prime = SecP256K1Curve.q - if (x >= prime) { - // Cannot have point co-ordinates larger than this as everything takes place modulo Q. - return null - } - // Compressed keys require you to know an extra bit of data about the y-coord as there are - // two possibilities. So it'DEFAULT_REGISTRY_ADDRESS encoded in the recId. - val r = decompressKey(x, recId and 1 == 1) - // 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers - // responsibility). - if (!r.multiply(n).isInfinity) { - return null - } - // 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification. - val e = BigInteger(1, messageHash) - // 1.6. For k from 1 to 2 do the following. (loop is outside this function via - // iterating recId) - // 1.6.1. Compute a candidate public key as: - // Q = mi(r) * (sR - eG) - // - // Where mi(x) is the modular multiplicative inverse. We transform this into the following: - // Q = (mi(r) * DEFAULT_REGISTRY_ADDRESS ** R) + (mi(r) * -e ** G) - // Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). - // In the above equation ** is point multiplication and + is point addition (the EC group - // operator). - // - // We can find the additive inverse by subtracting e from zero then taking the mod. For - // example the additive inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and - // -3 mod 11 = 8. - val eInv = BigInteger.ZERO.subtract(e).mod(n) - val rInv = sig.r.modInverse(n) - val srInv = rInv.multiply(sig.s).mod(n) - val eInvrInv = rInv.multiply(eInv).mod(n) - val q = ECAlgorithms.sumOfTwoMultiplies(CURVE.g, eInvrInv, r, srInv) - - val qBytes = q.getEncoded(false) - // We remove the prefix - return BigInteger(1, qBytes.copyOfRange(1, qBytes.size)) -} - -/** - * This function is taken from Kethereum - * Decompress a compressed public key (x-coord and low-bit of y-coord). - * */ -private fun decompressKey(xBN: BigInteger, yBit: Boolean): ECPoint { - val x9 = X9IntegerConverter() - val compEnc = x9.integerToBytes(xBN, 1 + x9.getByteLength(CURVE.curve)) - compEnc[0] = (if (yBit) 0x03 else 0x02).toByte() - return CURVE.curve.decodePoint(compEnc) -} - -/** - * This Function is adapted from the Kethereum implementation - * Given an arbitrary piece of text and an Ethereum message signature encoded in bytes, - * returns the public key that was used to sign it. This can then be compared to the expected - * public key to determine if the signature was correct. - * - * @param message the data that was signed - * @param signatureData The recoverable signature components - * @return the public key used to sign the message - * @throws SignatureException If the public key could not be recovered or if there was a - * signature format error. - */ -@Throws(SignatureException::class) -fun signedJwtToKey(message: ByteArray, signatureData: SignatureData): BigInteger { - - val header = signatureData.v - // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, - // 0x1D = second key with even y, 0x1E = second key with odd y - if (header < 27 || header > 34) { - throw SignatureException("Header byte out of range: $header") - } - - val sig = ECDSASignature(signatureData.r, signatureData.s) - - val messageHash = message.sha256() - val recId = header - 27 - return recoverFromSignature(recId, sig, messageHash) - ?: throw SignatureException("Could not recover public key from signature") -} - diff --git a/jwt/src/main/java/me/uport/sdk/jwt/JWTExceptions.kt b/jwt/src/main/java/me/uport/sdk/jwt/JWTExceptions.kt deleted file mode 100644 index 1df407f3..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/JWTExceptions.kt +++ /dev/null @@ -1,11 +0,0 @@ -package me.uport.sdk.jwt - -/** - * Thrown when the a JWT does not seem to have the proper format - */ -class JWTEncodingException(message: String) : IllegalArgumentException(message) - -/** - * Thrown when a JWT is invalid either because it is expired, not valid yet or the signature doesn't match - */ -class InvalidJWTException(message: String) : IllegalStateException(message) diff --git a/jwt/src/main/java/me/uport/sdk/jwt/JWTSignerAlgorithm.kt b/jwt/src/main/java/me/uport/sdk/jwt/JWTSignerAlgorithm.kt deleted file mode 100644 index 85d7a3ac..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/JWTSignerAlgorithm.kt +++ /dev/null @@ -1,28 +0,0 @@ -package me.uport.sdk.jwt - -import com.uport.sdk.signer.Signer -import com.uport.sdk.signer.getJoseEncoded -import com.uport.sdk.signer.signJWT -import me.uport.sdk.core.utf8 -import me.uport.sdk.jwt.model.JwtHeader - -/** - * Abstracts the signature to a recoverable/non-recoverable JOSE encoding based on the jwt header or algorithm provided during construction - * - * It supports "ES256K" and "ES256K-R" signing methods - */ -class JWTSignerAlgorithm(private val jwtHeader: JwtHeader) { - - constructor(algorithm: String) : this(JwtHeader(alg = algorithm)) - - suspend fun sign(payload: String, signer: Signer): String { - - val signatureData = signer.signJWT(payload.toByteArray(utf8)) - - return when (jwtHeader.alg) { - JwtHeader.ES256K -> signatureData.getJoseEncoded(false) - JwtHeader.ES256K_R -> signatureData.getJoseEncoded(true) - else -> throw JWTEncodingException("Unknown algorithm (${jwtHeader.alg}) requested for signing") - } - } -} \ No newline at end of file diff --git a/jwt/src/main/java/me/uport/sdk/jwt/JWTTools.kt b/jwt/src/main/java/me/uport/sdk/jwt/JWTTools.kt deleted file mode 100644 index 4c143d3c..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/JWTTools.kt +++ /dev/null @@ -1,352 +0,0 @@ -package me.uport.sdk.jwt - -import android.content.Context -import com.squareup.moshi.JsonAdapter -import com.uport.sdk.signer.* -import me.uport.sdk.core.* -import me.uport.sdk.ethrdid.EthrDIDResolver -import me.uport.sdk.httpsdid.HttpsDIDResolver -import me.uport.sdk.jsonrpc.JsonRPC -import me.uport.sdk.jwt.model.JwtHeader -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K_R -import me.uport.sdk.jwt.model.JwtPayload -import me.uport.sdk.serialization.mapAdapter -import me.uport.sdk.serialization.moshi -import me.uport.sdk.universaldid.DIDDocument -import me.uport.sdk.universaldid.PublicKeyEntry -import me.uport.sdk.universaldid.PublicKeyType.Companion.EcdsaPublicKeySecp256k1 -import me.uport.sdk.universaldid.PublicKeyType.Companion.Secp256k1SignatureVerificationKey2018 -import me.uport.sdk.universaldid.PublicKeyType.Companion.Secp256k1VerificationKey2018 -import me.uport.sdk.universaldid.UniversalDID -import me.uport.sdk.uportdid.UportDIDResolver -import org.kethereum.crypto.model.PUBLIC_KEY_SIZE -import org.kethereum.crypto.model.PublicKey -import org.kethereum.crypto.toAddress -import org.kethereum.encodings.decodeBase58 -import org.kethereum.extensions.toBigInteger -import org.kethereum.hashes.sha256 -import org.kethereum.model.SignatureData -import org.walleth.khex.clean0xPrefix -import org.walleth.khex.hexToByteArray -import java.math.BigInteger -import java.security.SignatureException - -/** - * Tools for Verifying, Creating, and Decoding uport JWTs - * - * the [timeProvider] defaults to [SystemTimeProvider] but you can configure it for testing or for "was valid at" scenarios - */ -class JWTTools( - private val timeProvider: ITimeProvider = SystemTimeProvider -) { - private val notEmpty: (String) -> Boolean = { !it.isEmpty() } - - init { - - // blank did declarations - val blankUportDID = "did:uport:2nQs23uc3UN6BBPqGHpbudDxBkeDRn553BB" - val blankEthrDID = "did:ethr:0x0000000000000000000000000000000000000000" - val blankHttpsDID = "did:https:example.com" - - // register default Ethr DID resolver if Universal DID is unable to resolve blank Ethr DID - if (!UniversalDID.canResolve(blankEthrDID)) { - val defaultRPC = JsonRPC(Networks.mainnet.rpcUrl) - UniversalDID.registerResolver(EthrDIDResolver(defaultRPC)) - } - - // register default Uport DID resolver if Universal DID is unable to resolve blank Uport DID - if (!UniversalDID.canResolve(blankUportDID)) { - val defaultRPC = JsonRPC(Networks.rinkeby.rpcUrl) - UniversalDID.registerResolver(UportDIDResolver(defaultRPC)) - } - - // register default https DID resolver if Universal DID is unable to resolve blank https DID - if (!UniversalDID.canResolve(blankHttpsDID)) { - UniversalDID.registerResolver(HttpsDIDResolver()) - } - } - - /** - * This coroutine method creates a signed JWT from a [payload] Map and an abstracted [Signer] - * You're also supposed to pass the [issuerDID] and can configure the algorithm used and expiry time - * - * @param payload a map containing the fields forming the payload of this JWT - * @param issuerDID a DID string that will be set as the `iss` field in the JWT payload. - * The signature produced by the signer should correspond to this DID. - * If the `iss` field is already part of the [payload], that will get overwritten. - * **The [issuerDID] is NOT checked for format, nor for a match with the signer.** - * @param signer a [Signer] that will produce the signature section of this JWT. - * The signature should correspond to the [issuerDID]. - * @param expiresInSeconds number of seconds of validity of this JWT. You may omit this param if - * an `exp` timestamp is already part of the [payload]. - * If there is no `exp` field in the payload and the param is not specified, - * it defaults to [DEFAULT_JWT_VALIDITY_SECONDS] - * @param algorithm defaults to `ES256K-R`. The signing algorithm for this JWT. - * Supported types are `ES256K` for uport DID and `ES256K-R` for ethr-did and the rest - * - */ - suspend fun createJWT(payload: Map, issuerDID: String, signer: Signer, expiresInSeconds: Long = DEFAULT_JWT_VALIDITY_SECONDS, algorithm: String = ES256K_R): String { - val mapAdapter = moshi.mapAdapter(String::class.java, Any::class.java) - - val mutablePayload = payload.toMutableMap() - - val header = JwtHeader(alg = algorithm) - - val iatSeconds = Math.floor(timeProvider.nowMs() / 1000.0).toLong() - val expSeconds = iatSeconds + expiresInSeconds - - mutablePayload["iat"] = iatSeconds - mutablePayload["exp"] = payload["exp"] ?: expSeconds - mutablePayload["iss"] = issuerDID - - @Suppress("SimplifiableCallChain", "ConvertCallChainIntoSequence") - val signingInput = listOf(header.toJson(), mapAdapter.toJson(mutablePayload)) - .map { it.toBase64UrlSafe() } - .joinToString(".") - - val jwtSigner = JWTSignerAlgorithm(header) - val signature: String = jwtSigner.sign(signingInput, signer) - return listOf(signingInput, signature).joinToString(".") - } - - /** - * @Deprecated Please use [createJWT] - */ - @Suppress("LongParameterList") - @Deprecated("This method has been deprecated in favor of `createJWT`", ReplaceWith("createJWT()")) - fun create(context: Context, payload: JwtPayload, rootHandle: String, derivationPath: String, prompt: String = "", recoverable: Boolean = false, callback: (err: Exception?, encodedJWT: String) -> Unit) { - //create header and convert the parts to json strings - val header = if (!recoverable) { - JwtHeader(alg = ES256K) - } else { - JwtHeader(alg = ES256K_R) - } - val headerJsonString = header.toJson() - val payloadJsonString = jwtPayloadAdapter.toJson(payload) - //base 64 encode the jwt parts - val headerEncodedString = headerJsonString.toBase64UrlSafe() - val payloadEncodedString = payloadJsonString.toBase64UrlSafe() - - //FIXME: UportHDSigner should not be expecting base64 payloads - val messageToSign = "$headerEncodedString.$payloadEncodedString".toBase64() - - UportHDSigner().signJwtBundle(context, rootHandle, derivationPath, messageToSign, prompt) { err, signature -> - val encodedJwt = "$headerEncodedString.$payloadEncodedString.${signature.getJoseEncoded(recoverable)}" - callback(err, encodedJwt) - } - } - - /** - * Decodes a jwt [token] - * @param token is a string of 3 parts separated by . - * @throws InvalidJWTException when the header or payload are empty or when they don't start with { (invalid json) - * @return the JWT Header,Payload and signature as parsed objects - */ - fun decode(token: String): Triple { - //Split token by . from jwtUtils - val (encodedHeader, encodedPayload, encodedSignature) = splitToken(token) - if (!notEmpty(encodedHeader)) - throw InvalidJWTException("Header cannot be empty") - else if (!notEmpty(encodedPayload)) - throw InvalidJWTException("Payload cannot be empty") - //Decode the pieces - val headerString = String(encodedHeader.decodeBase64()) - val payloadString = String(encodedPayload.decodeBase64()) - val signatureBytes = encodedSignature.decodeBase64() - - //Parse Json - if (headerString[0] != '{' || payloadString[0] != '{') - throw InvalidJWTException("Invalid JSON format, should start with {") - else { - val header = JwtHeader.fromJson(headerString) - ?: throw InvalidJWTException("unable to parse the JWT header for $token") - val payload = jwtPayloadAdapter.fromJson(payloadString) - ?: throw InvalidJWTException("unable to parse the JWT payload for $token") - return Triple(header, payload, signatureBytes) - } - } - - /** - * Decodes a JWT into it's 3 components, keeping the payload as a Map type - * - * This is useful for situations where the known [JwtPayload] fields are not enough. - */ - fun decodeRaw(token: String): Triple, ByteArray> { - //Split token by . from jwtUtils - val (encodedHeader, encodedPayload, encodedSignature) = splitToken(token) - if (!notEmpty(encodedHeader)) - throw InvalidJWTException("Header cannot be empty") - else if (!notEmpty(encodedPayload)) - throw InvalidJWTException("Payload cannot be empty") - //Decode the pieces - val headerString = String(encodedHeader.decodeBase64()) - val payloadString = String(encodedPayload.decodeBase64()) - val signatureBytes = encodedSignature.decodeBase64() - - //Parse Json - if (headerString[0] != '{' || payloadString[0] != '{') - throw InvalidJWTException("Invalid JSON format, should start with {") - else { - val header = JwtHeader.fromJson(headerString) - ?: throw InvalidJWTException("unable to parse the JWT header for $token") - val mapAdapter = moshi.mapAdapter(String::class.java, Any::class.java) - - val payload = mapAdapter.fromJson(payloadString) - ?: throw InvalidJWTException("unable to parse the JWT payload for $token") - - return Triple(header, payload, signatureBytes) - } - } - - - /** - * Verifies a jwt [token] - * @params jwt token - * @throws InvalidJWTException when the current time is not within the time range of payload iat and exp - * when no public key matches are found in the DID document - * @return a [JwtPayload] if the verification is successful and `null` if it fails - */ - suspend fun verify(token: String, auth: Boolean = false): JwtPayload { - val (header, payload, signatureBytes) = decode(token) - - if (payload.iat != null && payload.iat > (timeProvider.nowMs() / 1000 + TIME_SKEW)) { - throw InvalidJWTException("Jwt not valid yet (issued in the future) iat: ${payload.iat}") - } - - if (payload.exp != null && payload.exp <= (timeProvider.nowMs() / 1000 - TIME_SKEW)) { - throw InvalidJWTException("JWT has expired: exp: ${payload.exp}") - } - - val publicKeys = resolveAuthenticator(header.alg, payload.iss, auth) - - val signingInputBytes = token.substringBeforeLast('.').toByteArray(utf8) - - val sigData = signatureBytes.decodeJose() - - val signatureIsValid = verificationMethod[header.alg] - ?.invoke(publicKeys, sigData, signingInputBytes) - ?: throw JWTEncodingException("JWT algorithm ${header.alg} not supported") - - if (signatureIsValid) { - return payload - } else { - throw InvalidJWTException("Signature invalid for JWT. DID document for ${payload.iss} does not have any matching public keys") - } - - } - - /** - * maps known algorithms to the corresponding verification method - */ - private val verificationMethod = mapOf( - ES256K_R to ::verifyRecoverableES256K, - ES256K to ::verifyES256K - ) - - private fun verifyES256K(publicKeys: List, sigData: SignatureData, signingInputBytes: ByteArray): Boolean { - - val messageHash = signingInputBytes.sha256() - - val matches = publicKeys.map { pubKeyEntry -> - - val pkBytes = pubKeyEntry.publicKeyHex?.hexToByteArray() - ?: pubKeyEntry.publicKeyBase64?.decodeBase64() - ?: pubKeyEntry.publicKeyBase58?.decodeBase58() - ?: ByteArray(PUBLIC_KEY_SIZE) - PublicKey(pkBytes.toBigInteger()).normalize() - - }.filter { publicKey -> - - ecVerify(messageHash, sigData, publicKey) - } - - return matches.isNotEmpty() - } - - private fun verifyRecoverableES256K(publicKeys: List, sigData: SignatureData, signingInputBytes: ByteArray): Boolean { - - val recoveredPubKey: BigInteger = try { - signedJwtToKey(signingInputBytes, sigData) - } catch (e: SignatureException) { - BigInteger.ZERO - } - - val pubKeyNoPrefix = PublicKey(recoveredPubKey).normalize() - val recoveredAddress = pubKeyNoPrefix.toAddress().cleanHex.toLowerCase() - - val matches = publicKeys.map { pubKeyEntry -> - - val pkBytes = pubKeyEntry.publicKeyHex?.hexToByteArray() - ?: pubKeyEntry.publicKeyBase64?.decodeBase64() - ?: pubKeyEntry.publicKeyBase58?.decodeBase58() - ?: ByteArray(PUBLIC_KEY_SIZE) - val pubKey = PublicKey(pkBytes.toBigInteger()).normalize() - - (pubKeyEntry.ethereumAddress?.clean0xPrefix() ?: pubKey.toAddress().cleanHex) - - }.filter { ethereumAddress -> - - ethereumAddress.toLowerCase() == recoveredAddress - } - - return matches.isNotEmpty() - } - - /** - * This method obtains a [DIDDocument] corresponding to the [issuer] and returns a list of [PublicKeyEntry] - * that can be used to check JWT signatures - * - * @param [auth] decide if the returned list should also be filtered against the `authentication` - * entries in the DIDDocument - * - */ - suspend fun resolveAuthenticator(alg: String, issuer: String, auth: Boolean): List { - - if (alg !in verificationMethod.keys) { - throw JWTEncodingException("JWT algorithm '$alg' not supported") - } - - val doc: DIDDocument = UniversalDID.resolve(issuer) - - val authenticationKeys: List = if (auth) { - doc.authentication.map { it.publicKey } - } else { - emptyList() // return an empty list - } - - val authenticators = doc.publicKey.filter { - - // filter public keys which belong to the list of supported key types - supportedKeyTypes.contains(it.type) && (!auth || (authenticationKeys.contains(it.id))) - } - - if (auth && (authenticators.isEmpty())) throw InvalidJWTException("DID document for $issuer does not have public keys suitable for authenticating user") - if (authenticators.isEmpty()) throw InvalidJWTException("DID document for $issuer does not have public keys for $alg") - - return authenticators - } - - companion object { - //Create adapters with each object - val jwtPayloadAdapter: JsonAdapter by lazy { moshi.adapter(JwtPayload::class.java) } - - /** - * 5 minutes. The default number of seconds of validity of a JWT, in case no other interval is specified. - */ - const val DEFAULT_JWT_VALIDITY_SECONDS = 300L - - private const val TIME_SKEW = 300L - - /** - * List of supported key types for verifying DID JWT signatures - */ - val supportedKeyTypes = listOf( - Secp256k1VerificationKey2018, - Secp256k1SignatureVerificationKey2018, - EcdsaPublicKeySecp256k1 - ) - } - -} - diff --git a/jwt/src/main/java/me/uport/sdk/jwt/jwtUtils.kt b/jwt/src/main/java/me/uport/sdk/jwt/jwtUtils.kt deleted file mode 100644 index ceb4741d..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/jwtUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package me.uport.sdk.jwt - -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PRIVATE - -/** - * convenience method used during token processing. - * Splits JWT into parts. - * @throws IllegalArgumentException if it can't split or if the number of parts != 3 - */ -@VisibleForTesting(otherwise = PRIVATE) -fun splitToken(token: String): Triple { - val parts: List? = token.split('.', limit = 3) - if (parts !== null && parts.size == 3) { - return Triple(parts[0], parts[1], parts[2]) - } else { - throw IllegalArgumentException("Token must have 3 parts: Header, Payload, and Signature") - } -} \ No newline at end of file diff --git a/jwt/src/main/java/me/uport/sdk/jwt/model/Claim.kt b/jwt/src/main/java/me/uport/sdk/jwt/model/Claim.kt deleted file mode 100644 index 89d7a86b..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/model/Claim.kt +++ /dev/null @@ -1,11 +0,0 @@ -package me.uport.sdk.jwt.model - -import android.support.annotation.Keep - -@Keep -class Claim( - - val key: String, - - val value: String -) \ No newline at end of file diff --git a/jwt/src/main/java/me/uport/sdk/jwt/model/JwtHeader.kt b/jwt/src/main/java/me/uport/sdk/jwt/model/JwtHeader.kt deleted file mode 100644 index ec88bc90..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/model/JwtHeader.kt +++ /dev/null @@ -1,27 +0,0 @@ -package me.uport.sdk.jwt.model - -import android.support.annotation.Keep -import com.squareup.moshi.JsonAdapter -import me.uport.sdk.serialization.moshi - -/** - * Standard JWT header - */ -@Keep -class JwtHeader( - val typ: String = "JWT", - - val alg: String = ES256K -) { - - fun toJson(): String = jsonAdapter.toJson(this) - - companion object { - const val ES256K = "ES256K" - const val ES256K_R = "ES256K-R" - - fun fromJson(headerString: String): JwtHeader? = jsonAdapter.lenient().fromJson(headerString) - - private val jsonAdapter: JsonAdapter by lazy { moshi.adapter(JwtHeader::class.java) } - } -} \ No newline at end of file diff --git a/jwt/src/main/java/me/uport/sdk/jwt/model/JwtPayload.kt b/jwt/src/main/java/me/uport/sdk/jwt/model/JwtPayload.kt deleted file mode 100644 index a312ec8e..00000000 --- a/jwt/src/main/java/me/uport/sdk/jwt/model/JwtPayload.kt +++ /dev/null @@ -1,55 +0,0 @@ -package me.uport.sdk.jwt.model - -import android.support.annotation.Keep -import com.squareup.moshi.Json - -@Keep -data class JwtPayload( - - /** - * General - */ - val iss: String = "", //Cannot be null for signature verification - val iat: Long? = null, - val sub: String? = null, - val aud: String? = null, - val exp: Long? = null, - val callback: String? = null, - val type: String? = null, - - /** - * Specific to selective disclosure REQUEST - */ - val net: String? = null, - val act: String? = null, - val requested: List? = null, - val verified: List? = null, - val permissions: List? = null, - - /** - * Specific to selective disclosure RESPONSE - * Also includes verified - */ - val req: String? = null, //original jwt request, REQUIRED for sign selective disclosure responses - val nad: String? = null, //The MNID of the Ethereum account requested using act in the Selective Disclosure Request - val dad: String? = null, //The devicekey as a regular hex encoded ethereum address as requested using act='devicekey' in the Selective Disclosure Request - //val own: String?, //The self signed claims requested from a user. - @Json(name = "own") val own: Map? = null, - val capabilities: List? = null, //An array of JWT tokens giving client app the permissions requested. Currently a token allowing them to send push notifications - - /** - * Specific to Verification - * Also includes iss, sub, iat, exp, claim - */ - //val claims: Map?, //An object containing one or more claims about sub eg: {"name":"Carol Crypteau"} - @Json(name = "claim") val claims: Map? = null, - /** - * Specific to Private Chain - * Also includes dad - */ - val ctl: String? = null, //Ethereum address of the Meta Identity Manager used to control the account - val reg: String? = null, //Ethereum address of the Uport Registry used on private chain - val rel: String? = null, //Url of relay service for providing gas on private network - val fct: String? = null, //Url of fueling service for providing gas on private network - val acc: String? = null //Fuel token used to authenticate on above fct url -) \ No newline at end of file diff --git a/jwt/src/main/res/values/strings.xml b/jwt/src/main/res/values/strings.xml deleted file mode 100644 index 0d37cc73..00000000 --- a/jwt/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - JWT - diff --git a/jwt/src/main/res/values/styles.xml b/jwt/src/main/res/values/styles.xml deleted file mode 100644 index ca668843..00000000 --- a/jwt/src/main/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/jwt/src/test/java/me/uport/sdk/jwt/ECUtilsKtTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/ECUtilsKtTest.kt deleted file mode 100644 index 6b714bf9..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/ECUtilsKtTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package me.uport.sdk.jwt - -import assertk.assert -import assertk.assertions.isTrue -import org.junit.Test -import org.kethereum.crypto.model.PrivateKey -import org.kethereum.crypto.publicKeyFromPrivate -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.hashes.sha256 -import org.kethereum.model.SignatureData - -class ECUtilsKtTest { - - @Test - fun `can verify non recoverable JWT signature`() { - - val referencePayload = "Hello, world!".toByteArray() - - val referenceSignature = SignatureData( - r = "6bcd81446183af193ca4a172d5c5c26345903b24770d90b5d790f74a9dec1f68".hexToBigInteger(), - s = "e2b85b3c92c9b4f3cf58de46e7997d8efb6e14b2e532d13dfa22ee02f3a43d5d".hexToBigInteger() - ) - - val privateKey = PrivateKey("65fc670d9351cb87d1f56702fb56a7832ae2aab3427be944ab8c9f2a0ab87960".hexToBigInteger()) - val publicKey = publicKeyFromPrivate(privateKey) - - val messageHash = referencePayload.sha256() - val result = ecVerify(messageHash, referenceSignature, publicKey) - assert(result).isTrue() - } -} \ No newline at end of file diff --git a/jwt/src/test/java/me/uport/sdk/jwt/JWTDecodeTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/JWTDecodeTest.kt deleted file mode 100644 index bbbc87b9..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/JWTDecodeTest.kt +++ /dev/null @@ -1,96 +0,0 @@ -package me.uport.sdk.jwt - -import assertk.assert -import assertk.assertions.hasMessage -import assertk.assertions.isEqualTo -import assertk.assertions.isInstanceOf -import org.junit.Test - - -class JWTDecodeTest { - private val validShareReqToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiIyb2VYdWZIR0RwVTUxYmZLQnNaRGR1N0plOXdlSjNyN3NWRyIsImlhdCI6MTUyMDM2NjQzMiwicmVxdWVzdGVkIjpbIm5hbWUiLCJwaG9uZSIsImNvdW50cnkiLCJhdmF0YXIiXSwicGVybWlzc2lvbnMiOlsibm90aWZpY2F0aW9ucyJdLCJjYWxsYmFjayI6Imh0dHBzOi8vY2hhc3F1aS51cG9ydC5tZS9hcGkvdjEvdG9waWMvWG5IZnlldjUxeHNka0R0dSIsIm5ldCI6IjB4NCIsImV4cCI6MTUyMDM2NzAzMiwidHlwZSI6InNoYXJlUmVxIn0.C8mPCCtWlYAnroduqysXYRl5xvrOdx1r4iq3A3SmGDGZu47UGTnjiZCOrOQ8A5lZ0M9JfDpZDETCKGdJ7KUeWQ" - private val validTokenHeader = validShareReqToken.split('.')[0] - private val validShareReqTokenPayload = validShareReqToken.split('.')[1] - private val validShareReqTokenSignature = validShareReqToken.split('.')[2] - - private val validVerificationToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbSI6eyJuYW1lIjoiQm9iIiwiZ2VuZGVyIjoibWFsZSJ9LCJpYXQiOjE1NDk5MDg0MjQsImV4cCI6MTU0OTkwODcyNCwiaXNzIjoiZGlkOmV0aHI6MHhjZjAzZGQwYTg5NGVmNzljYjViNjAxYTQzYzRiMjVlM2FlNGM2N2VkIn0.ffjGFzoSfX-fS50GHhYkwA8It5034Rw8BczWslUcbfGI51uJSGbmhfJSfeGdEaPlFFgVrnRj1YBoG_oHrnEiBQA" - - private val invalidTokenOnlyHeader = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ." - private val invalidTokenEmptyPayload = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ..C8mPCCtWlYAnroduqysXYRl5xvrOdx1r4iq3A3SmGDGZu47UGTnjiZCOrOQ8A5lZ0M9JfDpZDETCKGdJ7KUeWQ" - private val invalidTokenEmptyHeader = ".eyJpc3MiOiIyb2VYdWZIR0RwVTUxYmZLQnNaRGR1N0plOXdlSjNyN3NWRyIsImlhdCI6MTUyMDM2NjQzMiwicmVxdWVzdGVkIjpbIm5hbWUiLCJwaG9uZSIsImNvdW50cnkiLCJhdmF0YXIiXSwicGVybWlzc2lvbnMiOlsibm90aWZpY2F0aW9ucyJdLCJjYWxsYmFjayI6Imh0dHBzOi8vY2hhc3F1aS51cG9ydC5tZS9hcGkvdjEvdG9waWMvWG5IZnlldjUxeHNka0R0dSIsIm5ldCI6IjB4NCIsImV4cCI6MTUyMDM2NzAzMiwidHlwZSI6InNoYXJlUmVxIn0.C8mPCCtWlYAnroduqysXYRl5xvrOdx1r4iq3A3SmGDGZu47UGTnjiZCOrOQ8A5lZ0M9JfDpZDETCKGdJ7KUeWQ" - - @Test - fun `can split complete token`() { - val parts = splitToken(validShareReqToken) - val expected = Triple( - validTokenHeader, - validShareReqTokenPayload, - validShareReqTokenSignature) - - assert(parts).isEqualTo(expected) - } - - @Test - fun `throws when splitting empty token`() { - assert { splitToken("") } - .thrownError { isInstanceOf(IllegalArgumentException::class) } - } - - @Test - fun `throws when splitting incomplete token`() { - assert { splitToken(invalidTokenOnlyHeader) } - .thrownError { isInstanceOf(IllegalArgumentException::class) } - } - - @Test - fun `decodes complete token`() { - val (header, payload) = JWTTools().decode(validShareReqToken) - assert(header.typ).isEqualTo("JWT") - assert(payload.iss).isEqualTo("2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG") - assert(payload.requested!![0]).isEqualTo("name") - } - - @Test - fun `decodes token with claims`() { - val (header, payload) = JWTTools().decode(validVerificationToken) - val nameClaim = mapOf("name" to "Bob", "gender" to "male") - assert(header.typ).isEqualTo("JWT") - assert(payload.claims).isEqualTo(nameClaim) - assert(payload.iss).isEqualTo("did:ethr:0xcf03dd0a894ef79cb5b601a43c4b25e3ae4c67ed") - } - - @Test - fun `throws when decoding incomplete token`() { - assert { JWTTools().decode((invalidTokenEmptyPayload)) } - .thrownError { - isInstanceOf(InvalidJWTException::class) - hasMessage("Payload cannot be empty") - } - - assert { JWTTools().decode((invalidTokenEmptyHeader)) } - .thrownError { - isInstanceOf(InvalidJWTException::class) - hasMessage("Header cannot be empty") - } - } - - @Test - fun `throws on random token parts`() { - assert { JWTTools().decode("blahhh.blahhh.blahhh") } - .thrownError { - isInstanceOf(InvalidJWTException::class) - } - - assert { JWTTools().decode("$validTokenHeader.blahhh.blahhh") } - .thrownError { - isInstanceOf(InvalidJWTException::class) - } - - assert { JWTTools().decode("blahhh.$validShareReqTokenPayload.blahhh") } - .thrownError { - isInstanceOf(InvalidJWTException::class) - } - - } - -} \ No newline at end of file diff --git a/jwt/src/test/java/me/uport/sdk/jwt/JWTSignerAlgorithmTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/JWTSignerAlgorithmTest.kt deleted file mode 100644 index 095cedf5..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/JWTSignerAlgorithmTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -package me.uport.sdk.jwt - -import assertk.assert -import assertk.assertions.isEqualTo -import com.uport.sdk.signer.KPSigner -import kotlinx.coroutines.runBlocking -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K -import me.uport.sdk.jwt.model.JwtHeader.Companion.ES256K_R -import org.junit.Test - -class JWTSignerAlgorithmTest { - - @Test - fun `can sign using non recoverable key algorithm`() = runBlocking { - - val signer = KPSigner("65fc670d9351cb87d1f56702fb56a7832ae2aab3427be944ab8c9f2a0ab87960") - - val expectedSignature = "a82BRGGDrxk8pKFy1cXCY0WQOyR3DZC115D3Sp3sH2jiuFs8ksm0889Y3kbnmX2O-24UsuUy0T36Iu4C86Q9XQ" - val signature = JWTSignerAlgorithm(ES256K).sign("Hello, world!", signer) - - assert(signature).isEqualTo(expectedSignature) - assert(signature.decodeBase64().size).isEqualTo(64) - - } - - @Test - fun `can sign using recoverable key algorithm`() = runBlocking { - - val signer = KPSigner("65fc670d9351cb87d1f56702fb56a7832ae2aab3427be944ab8c9f2a0ab87960") - - val expectedSignature = "a82BRGGDrxk8pKFy1cXCY0WQOyR3DZC115D3Sp3sH2jiuFs8ksm0889Y3kbnmX2O-24UsuUy0T36Iu4C86Q9XQE" - val signature = JWTSignerAlgorithm(ES256K_R).sign("Hello, world!", signer) - - assert(signature).isEqualTo(expectedSignature) - assert(signature.decodeBase64().size).isEqualTo(65) - - } - - @Test - fun `can sign using vector from did-jwt`() = runBlocking { - - val signer = KPSigner("278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f") - - //the signature data from https://github.com/uport-project/did-jwt/blob/develop/src/__tests__/__snapshots__/SimpleSigner-test.js.snap - // JOSE encoded with recovery param - val expectedSignature = "jsvdLwqr-O206hkegoq6pbo7LJjCaflEKHCvfohBP9XJ4C7mG2TPL9YjyKEpYSXqqkUrfRoCxQecHR11Uh7POwA" - - val signature = JWTSignerAlgorithm(ES256K_R).sign("thequickbrownfoxjumpedoverthelazyprogrammer", signer) - - assert(signature).isEqualTo(expectedSignature) - } -} \ No newline at end of file diff --git a/jwt/src/test/java/me/uport/sdk/jwt/JWTToolsJVMTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/JWTToolsJVMTest.kt deleted file mode 100644 index bd6e2ca9..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/JWTToolsJVMTest.kt +++ /dev/null @@ -1,281 +0,0 @@ -package me.uport.sdk.jwt - -import assertk.assert -import assertk.assertions.isEqualTo -import assertk.assertions.isInstanceOf -import assertk.assertions.isNotNull -import com.uport.sdk.signer.KPSigner -import io.mockk.coEvery -import io.mockk.mockkObject -import kotlinx.coroutines.runBlocking -import me.uport.sdk.ethrdid.EthrDIDDocument -import me.uport.sdk.jwt.model.JwtPayload -import me.uport.sdk.testhelpers.TestTimeProvider -import me.uport.sdk.testhelpers.coAssert -import me.uport.sdk.universaldid.UniversalDID -import me.uport.sdk.uportdid.UportDIDDocument -import org.junit.Test - -class JWTToolsJVMTest { - - private val tokens = listOf( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1MzUwMTY3MDIsImV4cCI6MTUzNTEwMzEwMiwiYXVkIjoiZGlkOmV0aHI6MHhhOWUzMjMyYjYxYmRiNjcyNzEyYjlhZTMzMTk1MDY5ZDhkNjUxYzFhIiwidHlwZSI6InNoYXJlUmVzcCIsIm5hZCI6IjJvZHpqVGFpOFJvNFYzS3hrbTNTblppdjlXU1l1Tm9aNEFoIiwib3duIjp7Im5hbWUiOiJ1UG9ydCBVc2VyIn0sInJlcSI6ImV5SjBlWEFpT2lKS1YxUWlMQ0poYkdjaU9pSkZVekkxTmtzdFVpSjkuZXlKcFlYUWlPakUxTXpVd01UWTJPREVzSW1WNGNDSTZNVFV6TlRBeE56STRNU3dpY21WeGRXVnpkR1ZrSWpwYkltNWhiV1VpTENKd2FHOXVaU0lzSW1OdmRXNTBjbmtpWFN3aWNHVnliV2x6YzJsdmJuTWlPbHNpYm05MGFXWnBZMkYwYVc5dWN5SmRMQ0pqWVd4c1ltRmpheUk2SW1oMGRIQnpPaTh2WTJoaGMzRjFhUzUxY0c5eWRDNXRaUzloY0drdmRqRXZkRzl3YVdNdmJVVXpTbVpXZWxOMFNuUnFhbnBvWWpSYVRFRnhkeUlzSW1GamRDSTZJbXRsZVhCaGFYSWlMQ0owZVhCbElqb2ljMmhoY21WU1pYRWlMQ0pwYzNNaU9pSmthV1E2WlhSb2Nqb3dlR0U1WlRNeU16SmlOakZpWkdJMk56STNNVEppT1dGbE16TXhPVFV3Tmpsa09HUTJOVEZqTVdFaWZRLnVScUdGd01XNnpWSDR4OWFmTDAtS29qSEYwVF9GbW9QWnR6OG5uSjRFXzhNY2cxejBBZ21aMnplOE5iS05wVUNnRHRwTU9RNzVGSjU4WmhzbWFxQUxBRSIsImNhcGFiaWxpdGllcyI6WyJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5rc3RVaUo5LmV5SnBZWFFpT2pFMU16VXdNVFkzTURFc0ltVjRjQ0k2TVRVek5qTXhNamN3TVN3aVlYVmtJam9pWkdsa09tVjBhSEk2TUhoaE9XVXpNak15WWpZeFltUmlOamN5TnpFeVlqbGhaVE16TVRrMU1EWTVaRGhrTmpVeFl6RmhJaXdpZEhsd1pTSTZJbTV2ZEdsbWFXTmhkR2x2Ym5NaUxDSjJZV3gxWlNJNkltRnlianBoZDNNNmMyNXpPblZ6TFhkbGMzUXRNam94TVRNeE9UWXlNVFkxTlRnNlpXNWtjRzlwYm5RdlIwTk5MM1ZRYjNKMEx6UXpNRGsxTWpZMkxUSmhPR1F0TTJFMFpTMWlaRFV3TFRka01USm1ZVE00TWpRNFlpSXNJbWx6Y3lJNkltUnBaRHBsZEdoeU9qQjRNVEE0TWpBNVpqUXlORGRpTjJabE5qWXdOV0l3WmpVNFpqa3hORFZsWXpNeU5qbGtNREUxTkNKOS5Lc0F6TmVDeHFDaF9rMkt4aTYtWHFveFNXZjBCLWFFR0xXdi1ldHVXQlF2QU5neDFTMG5oZ0ppRkllUnRXakw4ekdnVVV3MUlsSWJtYUZrOEo5aGdhd0UiXSwiYm94UHViIjoiY2g3aGI2S3hsakJ2bXh5UDJXZENWTFNTLzQ2S1hCcmdkWG1Mcm03VEpIST0iLCJpc3MiOiJkaWQ6ZXRocjoweDEwODIwOWY0MjQ3YjdmZTY2MDViMGY1OGY5MTQ1ZWMzMjY5ZDAxNTQifQ.Ncf8B_y0Ha8gdaYyCaL5jLX2RsKTMwxTQ8KlybXFygsxKUUQm9OXo4lU65fduIaFvVyPOP6Oe2adar8m0m2aiwA", - "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1MzUwMTY1OTcsImV4cCI6MTUzNTEwMjk5NywiYXVkIjoiZGlkOmV0aHI6MHhhOWUzMjMyYjYxYmRiNjcyNzEyYjlhZTMzMTk1MDY5ZDhkNjUxYzFhIiwidHlwZSI6InNoYXJlUmVzcCIsIm5hZCI6IjJvd2hGdGRtc0VVNVVWMVNCbld0RnZZcHlUcjNqNHd5TmR2Iiwib3duIjp7Im5hbWUiOiJ1UG9ydCBVc2VyIn0sInJlcSI6ImV5SjBlWEFpT2lKS1YxUWlMQ0poYkdjaU9pSkZVekkxTmtzdFVpSjkuZXlKcFlYUWlPakUxTXpVd01UWTFPRGdzSW1WNGNDSTZNVFV6TlRBeE56RTRPQ3dpY21WeGRXVnpkR1ZrSWpwYkltNWhiV1VpTENKd2FHOXVaU0lzSW1OdmRXNTBjbmtpWFN3aWNHVnliV2x6YzJsdmJuTWlPbHNpYm05MGFXWnBZMkYwYVc5dWN5SmRMQ0pqWVd4c1ltRmpheUk2SW1oMGRIQnpPaTh2WTJoaGMzRjFhUzUxY0c5eWRDNXRaUzloY0drdmRqRXZkRzl3YVdNdldtMXNOa2xuUWsxYU9XUXhWbGgwV0ZsYVJUTlBkeUlzSW1GamRDSTZJbXRsZVhCaGFYSWlMQ0owZVhCbElqb2ljMmhoY21WU1pYRWlMQ0pwYzNNaU9pSmthV1E2WlhSb2Nqb3dlR0U1WlRNeU16SmlOakZpWkdJMk56STNNVEppT1dGbE16TXhPVFV3Tmpsa09HUTJOVEZqTVdFaWZRLnRNbWh6cjFkbER0YUhUeWUtVDAxOGp2N0NUYlRhVWY4ZzlhbHNxVWJ6VGpGUkFsbV9qZ2RaR3pVVEVzeGtBY0ZmVy1ZSmpIVGtwSmtjNFNWREc3REJBQSIsImlzcyI6ImRpZDpldGhyOjB4ZThjOTFiZGU3NjI1YWIyYzBlZDlmMjE0ZGViMzk0NDBkYTdlMDNjNCJ9.-04Z_m2kgFBwF1Elh3jmv1_44jdGjEczf4x3c5Z4TxwiMP8nXZsIDVgsp3PS34DPGfpR4OkZ6LBozBBER3TABAA" - ) - - @Test - fun `verifies simple tokens`() = runBlocking { - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve("did:ethr:0x108209f4247b7fe6605b0f58f9145ec3269d0154") }.returns(EthrDIDDocument.fromJson("""{"id":"did:ethr:0x108209f4247b7fe6605b0f58f9145ec3269d0154","publicKey":[{"id":"did:ethr:0x108209f4247b7fe6605b0f58f9145ec3269d0154#owner","type":"Secp256k1VerificationKey2018","owner":"did:ethr:0x108209f4247b7fe6605b0f58f9145ec3269d0154","ethereumAddress":"0x108209f4247b7fe6605b0f58f9145ec3269d0154","publicKeyHex":null,"publicKeyBase64":null,"publicKeyBase58":null,"value":null}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:ethr:0x108209f4247b7fe6605b0f58f9145ec3269d0154#owner"}],"service":[],"@context":"https://w3id.org/did/v1"}""")) - coEvery { UniversalDID.resolve("did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4") }.returns(EthrDIDDocument.fromJson("""{"id":"did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4","publicKey":[{"id":"did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#owner","type":"Secp256k1VerificationKey2018","owner":"did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4","ethereumAddress":"0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4","publicKeyHex":null,"publicKeyBase64":null,"publicKeyBase58":null,"value":null}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#owner"}],"service":[],"@context":"https://w3id.org/did/v1"}""")) - - tokens.forEach { token -> - val payload = JWTTools(TestTimeProvider(1535102500000L)).verify(token) - assert(payload).isNotNull() - } - } - - private val validShareReqToken1 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiIyb2VYdWZIR0RwVTUxYmZLQnNaRGR1N0plOXdlSjNyN3NWRyIsImlhdCI6MTUyMDM2NjQzMiwicmVxdWVzdGVkIjpbIm5hbWUiLCJwaG9uZSIsImNvdW50cnkiLCJhdmF0YXIiXSwicGVybWlzc2lvbnMiOlsibm90aWZpY2F0aW9ucyJdLCJjYWxsYmFjayI6Imh0dHBzOi8vY2hhc3F1aS51cG9ydC5tZS9hcGkvdjEvdG9waWMvWG5IZnlldjUxeHNka0R0dSIsIm5ldCI6IjB4NCIsImV4cCI6MTUyMDM2NzAzMiwidHlwZSI6InNoYXJlUmVxIn0.C8mPCCtWlYAnroduqysXYRl5xvrOdx1r4iq3A3SmGDGZu47UGTnjiZCOrOQ8A5lZ0M9JfDpZDETCKGdJ7KUeWQ" - private val expectedShareReqPayload1 = JwtPayload(iss = "2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG", iat = 1520366432, sub = null, aud = null, exp = 1520367032, callback = "https://chasqui.uport.me/api/v1/topic/XnHfyev51xsdkDtu", type = "shareReq", net = "0x4", act = null, requested = listOf("name", "phone", "country", "avatar"), verified = null, permissions = listOf("notifications"), req = null, nad = null, dad = null, own = null, capabilities = null, claims = null, ctl = null, reg = null, rel = null, fct = null, acc = null) - - private val incomingJwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiIyb21SSlpMMjNaQ1lnYzFyWnJGVnBGWEpwV29hRUV1SlVjZiIsImlhdCI6MTUxOTM1MDI1NiwicGVybWlzc2lvbnMiOlsibm90aWZpY2F0aW9ucyJdLCJjYWxsYmFjayI6Imh0dHBzOi8vYXBpLnVwb3J0LnNwYWNlL29sb3J1bi9jcmVhdGVJZGVudGl0eSIsIm5ldCI6IjB4MzAzOSIsImFjdCI6ImRldmljZWtleSIsImV4cCI6MTUyMjU0MDgwMCwidHlwZSI6InNoYXJlUmVxIn0.EkqNUyrZhcDbTQl73XpL2tp470lCo2saMXzuOZ91UI2y-XzpcBMzhhSeUORnoJXJhHnkGGpshZlESWUgrbuiVQ" - private val expectedJwtPayload = JwtPayload(iss = "2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf", iat = 1519350256, sub = null, aud = null, exp = 1522540800, callback = "https://api.uport.space/olorun/createIdentity", type = "shareReq", net = "0x3039", act = "devicekey", requested = null, verified = null, permissions = listOf("notifications"), req = null, nad = null, dad = null, own = null, capabilities = null, claims = null, ctl = null, reg = null, rel = null, fct = null, acc = null) - - @Test - fun `returns correct payload after successful verification`() = runBlocking { - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve("2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG") }.returns(UportDIDDocument.fromJson("""{"id":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG","publicKey":[{"id":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG#keys-1","type":"Secp256k1VerificationKey2018","owner":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG","publicKeyHex":"04171fcc7654cad14745b9835bc534d8e59038ae6929c793d7f8dd2c934580ca39ff1e2de3d7ef69a8daba5e5590d3ec80486a273cbe2bd1b76ebd01f949b41463"}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:uport:2oeXufHGDpU51bfKBsZDdu7Je9weJ3r7sVG#keys-1"}],"service":[],"@context":"https://w3id.org/did/v1","uportProfile":{"@type":"App","image":{"@type":"ImageObject","name":"avatar","contentUrl":"/ipfs/Qmez4bdFmxPknbAoGzHmpjpLjQFChq39h5UMPGiwUHgt8f"},"name":"uPort Demo","description":"Demo App"}}""")) - coEvery { UniversalDID.resolve("2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf") }.returns(UportDIDDocument.fromJson("""{"id":"did:uport:2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf","publicKey":[{"id":"did:uport:2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf#keys-1","type":"Secp256k1VerificationKey2018","owner":"did:uport:2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf","publicKeyHex":"0422d2edad30d8588c0661e032f37af8177cfa0a056ee9b8ca953b07c6600a637c002ed22fe6612e28e558aee130d399ba97f89e25c16661a99c8af8c832b88568"}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:uport:2omRJZL23ZCYgc1rZrFVpFXJpWoaEEuJUcf#keys-1"}],"service":[],"@context":"https://w3id.org/did/v1","uportProfile":{"@type":"App","image":{"@type":"ImageObject","name":"avatar","contentUrl":"/ipfs/QmdznPoNSnc6RawSzzvNFX5HerF62Vu7sbP3vSur9gDFGb"},"name":"Olorun","description":"Private network configuration service"}}""")) - - val shareReqPayload = JWTTools(TestTimeProvider(1520366666000L)).verify(validShareReqToken1) - assert(shareReqPayload).isEqualTo(expectedShareReqPayload1) - - val incomingJwtPayload = JWTTools(TestTimeProvider(1522540300000L)).verify(incomingJwt) - assert(incomingJwtPayload).isEqualTo(expectedJwtPayload) - } - - @Test - fun `throws when given an unknown algorithm to create tokens`() { - val tested = JWTTools() - - val payload = emptyMap() - val signer = KPSigner("0x1234") - val issuerDID = "did:ethr:${signer.getAddress()}" - - coAssert { - tested.createJWT(payload, issuerDID, signer, algorithm = "some fancy but unknown algorithm") - }.thrownError { - isInstanceOf(JWTEncodingException::class) - } - } - - - @Test - fun `throws when a token is issued in the future`() { - val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXRocjoweGE5ZTMyMzJiNjFiZGI2NzI3MTJiOWFlMzMxOTUwNjlkOGQ2NTFjMWEiLCJpYXQiOjE1NDU1Njk1NDEsImV4cCI6MTU0NjA4Nzk0MSwiYXVkIjoiZGlkOmV0aHI6MHgxMDgyMDlmNDI0N2I3ZmU2NjA1YjBmNThmOTE0NWVjMzI2OWQwMTU0Iiwic3ViIjoiIn0.Bt9Frc1QabJfpXYBoU4sns8WPeRLdKU87FncgMFq1lY" - - coAssert { - JWTTools(TestTimeProvider(977317692000L)).verify(token) - }.thrownError { - isInstanceOf(InvalidJWTException::class) - } - } - - @Test - fun `throws when a token is expired`() { - val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXRocjoweGE5ZTMyMzJiNjFiZGI2NzI3MTJiOWFlMzMxOTUwNjlkOGQ2NTFjMWEiLCJpYXQiOjE1NDU1Njk1NDEsImV4cCI6MTU0NjA4Nzk0MSwiYXVkIjoiZGlkOmV0aHI6MHgxMDgyMDlmNDI0N2I3ZmU2NjA1YjBmNThmOTE0NWVjMzI2OWQwMTU0Iiwic3ViIjoiIn0.Bt9Frc1QabJfpXYBoU4sns8WPeRLdKU87FncgMFq1lY" - - coAssert { - JWTTools(TestTimeProvider(1576847292000L)).verify(token) - }.thrownError { - isInstanceOf(InvalidJWTException::class) - } - } - - @Test - fun `throws when the signature does not match any public keys belonging to the issuer`() { - - mockkObject(UniversalDID) - coEvery { UniversalDID.resolve("did:ethr:0x6985a110df37555235d7d0de0a0fb28c9848dfa9") }.returns(EthrDIDDocument.fromJson("""{"id":"did:ethr:0x6985a110df37555235d7d0de0a0fb28c9848dfa9","publicKey":[{"id":"did:ethr:0x6985a110df37555235d7d0de0a0fb28c9848dfa9#owner","type":"Secp256k1VerificationKey2018","owner":"did:ethr:0x6985a110df37555235d7d0de0a0fb28c9848dfa9","ethereumAddress":"0x6985a110df37555235d7d0de0a0fb28c9848dfa9","publicKeyHex":null,"publicKeyBase64":null,"publicKeyBase58":null,"value":null}],"authentication":[{"type":"Secp256k1SignatureAuthentication2018","publicKey":"did:ethr:0x6985a110df37555235d7d0de0a0fb28c9848dfa9#owner"}],"service":[],"@context":"https://w3id.org/did/v1"}""")) - - // JWT token with a Signer that doesn't have anything to do with the issuerDID. - val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NDY4NTkxNTksImV4cCI6MTg2MjIxOTE1OSwiaXNzIjoiZGlkOmV0aHI6MHg2OTg1YTExMGRmMzc1NTUyMzVkN2QwZGUwYTBmYjI4Yzk4NDhkZmE5In0.fe1rvAHsoJsJzwSFAmVFTz9uxhncNY65jpbb2cS9jcY08xphpU3rOy1N85_IbEjhIZw-FrPeFgxJLoDLw6itcgE" - - coAssert { - JWTTools(TestTimeProvider(1547818630000L)).verify(token) - }.thrownError { - isInstanceOf(InvalidJWTException::class) - } - } - - - @Test - fun `finds public key`() = runBlocking { - - val alg = "ES256K" - val issuer = "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4" - val auth = false - val doc = EthrDIDDocument.fromJson(""" - { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKey": [{ - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-1", - "type": "Secp256k1VerificationKey2018", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }], - "authentication": [], - "service": [], - "@context": "https://w3id.org/did/v1" - } - """) - - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve(issuer) }.returns(doc) - - val authenticators = JWTTools().resolveAuthenticator(alg, issuer, auth) - assert(authenticators).isEqualTo(doc.publicKey) - } - - @Test - fun `only list authenticators able to authenticate a user`() = runBlocking { - - val alg = "ES256K" - val issuer = "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4" - val auth = true - val doc = EthrDIDDocument.fromJson(""" - { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKey": [{ - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-1", - "type": "Secp256k1VerificationKey2018", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }, { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-2", - "type": "Secp256k1SignatureVerificationKey2018", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }, { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-3", - "type": "Secp256k1SignatureAuthentication2018", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }, { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-3", - "type": "Curve25519EncryptionPublicKey", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }], - "authentication": [{ - "type": "Secp256k1VerificationKey2018", - "publicKey": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-1" - }, { - "type": "Secp256k1SignatureVerificationKey2018", - "publicKey": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-2" - }], - "service": [], - "@context": "https://w3id.org/did/v1" - } - """) - - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve(issuer) }.returns(doc) - - val authenticators = JWTTools().resolveAuthenticator(alg, issuer, auth) - - assert(authenticators).isEqualTo(listOf(doc.publicKey[0], doc.publicKey[1])) - } - - @Test - fun `errors if no suitable public keys exist for authentication`() = runBlocking { - - val alg = "ES256K" - val issuer = "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4" - val auth = true - val doc = EthrDIDDocument.fromJson(""" - { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKey": [{ - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4#keys-1", - "type": "Secp256k1VerificationKey2018", - "owner": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKeyHex": "04613bb3a4874d27032618f020614c21cbe4c4e4781687525f6674089f9bd3d6c7f6eb13569053d31715a3ba32e0b791b97922af6387f087d6b5548c06944ab061" - }], - "authentication": [], - "service": [], - "@context": "https://w3id.org/did/v1" - } - """) - - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve(issuer) }.returns(doc) - - coAssert { - JWTTools().resolveAuthenticator(alg, issuer, auth) - }.thrownError { - isInstanceOf(InvalidJWTException::class) - } - } - - @Test - fun `errors if no public keys exist`() = runBlocking { - - val alg = "ES256K" - val issuer = "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4" - val auth = false - val doc = EthrDIDDocument.fromJson(""" - { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKey": [], - "authentication": [], - "service": [], - "@context": "https://w3id.org/did/v1" - } - """) - - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve(issuer) }.returns(doc) - - coAssert { - JWTTools().resolveAuthenticator(alg, issuer, auth) - }.thrownError { - isInstanceOf(InvalidJWTException::class) - } - } - - @Test - fun `errors if no supported signature types exist`() = runBlocking { - - val alg = "ESBAD" - val issuer = "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4" - val auth = false - val doc = EthrDIDDocument.fromJson(""" - { - "id": "did:ethr:0xe8c91bde7625ab2c0ed9f214deb39440da7e03c4", - "publicKey": [], - "authentication": [], - "service": [], - "@context": "https://w3id.org/did/v1" - } - """) - - mockkObject(UniversalDID) - - coEvery { UniversalDID.resolve(issuer) }.returns(doc) - - coAssert { - JWTTools().resolveAuthenticator(alg, issuer, auth) - }.thrownError { - isInstanceOf(JWTEncodingException::class) - } - } -} - - diff --git a/jwt/src/test/java/me/uport/sdk/jwt/KeyRecoveryTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/KeyRecoveryTest.kt deleted file mode 100644 index 61cc560c..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/KeyRecoveryTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package me.uport.sdk.jwt - -import com.uport.sdk.signer.KPSigner -import com.uport.sdk.signer.signJWT -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.kethereum.crypto.model.PrivateKey -import org.kethereum.crypto.publicKeyFromPrivate -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.extensions.toHexStringNoPrefix -import org.kethereum.hashes.sha256 -import org.walleth.khex.toHexString - -class KeyRecoveryTest { - - // Uncomment `@Test` to iterate over 1000 * 1000 key/message combinations. Takes a lot of time. - //@Test - fun `can recover key from JWT signature`() = runBlocking { - for (i in 0 until 1000) { - val privateKey = "super secret $i".toByteArray().sha256().toHexString() - val pubKey = publicKeyFromPrivate(PrivateKey(privateKey.hexToBigInteger())).key.toHexStringNoPrefix() - val signer = KPSigner(privateKey) - println("trying key $i on 1000 messages") - for (j in 0 until 1000) { - val message = "hello $i".toByteArray(Charsets.UTF_8) - - val sigData = signer.signJWT(message) - - val recovered = signedJwtToKey(message, sigData).toHexStringNoPrefix() - - assertEquals("failed at key $i, message $j", pubKey, recovered) - } - } - } - -} \ No newline at end of file diff --git a/jwt/src/test/java/me/uport/sdk/jwt/model/JWTAlgorithmTest.kt b/jwt/src/test/java/me/uport/sdk/jwt/model/JWTAlgorithmTest.kt deleted file mode 100644 index b9802474..00000000 --- a/jwt/src/test/java/me/uport/sdk/jwt/model/JWTAlgorithmTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -package me.uport.sdk.jwt.model - -import assertk.assert -import assertk.assertions.isEqualTo -import assertk.assertions.isNotNull -import org.junit.Test - -class JWTAlgorithmTest { - - @Test - fun `can encode to json`() { - val result = JwtHeader("hello", "world").toJson() - //language=JSON - assert(result).isEqualTo("""{"typ":"hello","alg":"world"}""") - } - - @Test - fun `can decode json`() { - //language=JSON - val result = JwtHeader.fromJson("""{"typ":"hello","alg":"world"}""") - assert(result).isNotNull() - } - - @Test - fun `can decode lenient json`() { - val result = JwtHeader.fromJson("""{typ:"hello",alg:"world"}""") - assert(result).isNotNull() - } -} \ No newline at end of file diff --git a/publishing.gradle b/publishing.gradle index 9f289a23..c6c23de4 100644 --- a/publishing.gradle +++ b/publishing.gradle @@ -12,7 +12,7 @@ subprojects { subproject -> afterEvaluate { - if (subproject.plugins.hasPlugin('com.github.dcendents.android-maven')) { + if (subproject.plugins.hasPlugin('com.github.dcendents.android-maven') || subproject.plugins.hasPlugin('maven')) { subproject.group = groupID subproject.version = uport_sdk_version @@ -22,7 +22,9 @@ subprojects { subproject -> install { repositories.mavenInstaller { pom.project { - packaging 'aar' + if (subproject.hasProperty("android")) { + packaging 'aar' + } groupId subproject.group artifactId subproject.name @@ -72,6 +74,7 @@ subprojects { subproject -> user = getBintrayUser() key = getBintrayApiKey() + //noinspection GroovyAccessibility configurations = ['archives'] pkg { diff --git a/sdk/build.gradle b/sdk/build.gradle index b46f4277..54dc016c 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -3,6 +3,7 @@ apply plugin: "kotlin-android" apply plugin: "bivrost" apply plugin: "com.github.dcendents.android-maven" apply plugin: "com.jfrog.bintray" +apply plugin: "kotlinx-serialization" project.ext.description = "wrapper library for the uPort SDK" @@ -14,8 +15,6 @@ android { targetSdkVersion target_sdk_version testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - multiDexEnabled true } buildTypes { @@ -23,27 +22,24 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } - } + debug { + multiDexEnabled true + } + } } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "com.android.support:support-annotations:$support_lib_version" implementation "com.squareup.moshi:moshi-kotlin:$moshi_version" implementation "com.github.gnosis.bivrost-kotlin:bivrost-solidity-types:$bivrost_version" - api project(":signer") - api project(":identity") - api project(":core") - api project(":jsonrpc") - api project(":universal-did") - api project(":ethr-did") - api project(":uport-did") - api project(":https-did") + api "com.github.uport-project.kotlin-did-jwt:jwt:$did_jwt_version" api project(":credentials") api project(":transport") + api project(":identity") androidTestImplementation "com.android.support.test:runner:$test_runner_version" androidTestImplementation "com.android.support.test:rules:$test_runner_version" diff --git a/sdk/src/androidTest/java/me/uport/sdk/UportTest.kt b/sdk/src/androidTest/java/me/uport/sdk/UportTest.kt index 47647341..af515e6a 100644 --- a/sdk/src/androidTest/java/me/uport/sdk/UportTest.kt +++ b/sdk/src/androidTest/java/me/uport/sdk/UportTest.kt @@ -3,10 +3,9 @@ package me.uport.sdk import android.content.Context -import android.os.Looper import android.support.test.InstrumentationRegistry import assertk.all -import assertk.assert +import assertk.assertThat import assertk.assertions.doesNotContain import assertk.assertions.isEqualTo import assertk.assertions.isNotEqualTo @@ -15,11 +14,9 @@ import assertk.assertions.isNull import com.uport.sdk.signer.UportHDSigner import kotlinx.coroutines.runBlocking import me.uport.sdk.core.Networks -import me.uport.sdk.identity.Account +import me.uport.sdk.identity.HDAccount import org.junit.Before import org.junit.Test -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit class UportTest { @@ -28,7 +25,7 @@ class UportTest { @Before fun run_before_every_test() { context = InstrumentationRegistry.getTargetContext() - val config = Uport.Configuration() + val config = Configuration() .setApplicationContext(context) Uport.initialize(config) @@ -44,51 +41,15 @@ class UportTest { runBlocking { val acc = tested.createAccount(Networks.rinkeby.networkId) - assert(acc).all { + assertThat(acc).all { isNotNull() - isNotEqualTo(Account.blank) + isNotEqualTo(HDAccount.blank) } - assert(tested.defaultAccount).isNotNull() + assertThat(tested.defaultAccount).isNotNull() } } - @Test - fun there_can_be_only_one_default_account() { - - val tested = Uport - - tested.defaultAccount?.let { tested.deleteAccount(it) } - - runBlocking { - - val acc1 = tested.createAccount(Networks.rinkeby.networkId) - - assert(tested.defaultAccount).isEqualTo(acc1) //first account gets to be default - assert(tested.allAccounts().filter { it.isDefault == true }.size).isEqualTo(1) - - val acc2 = tested.createAccount(Networks.rinkeby.networkId) - - assert(tested.defaultAccount).isNotEqualTo(acc2) //default isn't overwritten - assert(tested.allAccounts().filter { it.isDefault == true }.size).isEqualTo(1) //still one default - - tested.defaultAccount = acc2 - - assert(tested.allAccounts().filter { it.isDefault == true }.size).isEqualTo(1) //still one default - } - } - - @Test - fun account_completion_called_on_main_thread() { - val latch = CountDownLatch(1) - Uport.createAccount(Networks.rinkeby) { _, _ -> - - assert(Looper.getMainLooper().isCurrentThread) - - latch.countDown() - } - latch.await(15, TimeUnit.SECONDS) - } @Test fun account_can_be_imported() { @@ -99,14 +60,14 @@ class UportTest { runBlocking { val account = tested.createAccount(Networks.rinkeby.networkId, referenceSeedPhrase) - assert(account).all { + assertThat(account).all { isNotNull() - isNotEqualTo(Account.blank) + isNotEqualTo(HDAccount.blank) } - assert(account.address).isEqualTo("2opxPamUQoLarQHAoVDKo2nDNmfQLNCZif4") - assert(account.publicAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") - assert(account.deviceAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") - assert(account.handle).isEqualTo("0x794adde0672914159c1b77dd06d047904fe96ac8") + assertThat(account.address).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.publicAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.deviceAddress).isEqualTo("0x847e5e3e8b2961c2225cb4a2f719d5409c7488c6") + assertThat(account.handle).isEqualTo("0x794adde0672914159c1b77dd06d047904fe96ac8") } } @@ -117,7 +78,7 @@ class UportTest { runBlocking { val refAccount = tested.createAccount(Networks.rinkeby.networkId, referenceSeedPhrase) - assert(tested.getAccount("0x794adde0672914159c1b77dd06d047904fe96ac8")).isEqualTo(refAccount) + assertThat(tested.getAccount("0x794adde0672914159c1b77dd06d047904fe96ac8")).isEqualTo(refAccount) } } @@ -129,17 +90,16 @@ class UportTest { runBlocking { val account = tested.createAccount(Networks.rinkeby.networkId) - assert(account).all { + assertThat(account).all { isNotNull() - isNotEqualTo(Account.blank) + isNotEqualTo(HDAccount.blank) } val root = account.handle tested.deleteAccount(root) - assert(UportHDSigner().allHDRoots(context)).doesNotContain(root) - assert(tested.defaultAccount).isNull() + assertThat(UportHDSigner().allHDRoots(context)).doesNotContain(root) + assertThat(tested.defaultAccount).isNull() } } - } \ No newline at end of file diff --git a/sdk/src/main/java/me/uport/sdk/AccountStorage.kt b/sdk/src/main/java/me/uport/sdk/AccountStorage.kt index 57634534..0496792f 100644 --- a/sdk/src/main/java/me/uport/sdk/AccountStorage.kt +++ b/sdk/src/main/java/me/uport/sdk/AccountStorage.kt @@ -1,7 +1,12 @@ package me.uport.sdk import android.content.SharedPreferences +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json import me.uport.sdk.identity.Account +import me.uport.sdk.identity.AccountType +import me.uport.sdk.identity.HDAccount +import me.uport.sdk.identity.MetaIdentityAccount interface AccountStorage { fun upsert(newAcc: Account) @@ -13,56 +18,97 @@ interface AccountStorage { fun all(): List fun upsertAll(list: Collection) + + /** + * sets the default account using its handle + */ + fun setAsDefault(accountHandle: String) + + /** + * fetches the default account + */ + fun getDefaultAccount(): Account? } /** * An account storage mechanism that relies on [SharedPreferences] for persistence to disk * + * Accounts are serialized then wrapped in an AccountHolder then along with the AccountType and isDefault + * * Accounts are loaded during construction and then relayed from memory */ class SharedPrefsAccountStorage( private val prefs: SharedPreferences ) : AccountStorage { - private val accounts = mapOf().toMutableMap() + private val accounts = mapOf().toMutableMap() init { prefs.getStringSet(KEY_ACCOUNTS, emptySet()) .orEmpty() .forEach { serialized -> - val acc = try { - Account.fromJson(serialized) + val accountHolder = try { + AccountHolder.fromJson(serialized) } catch (ex: Exception) { null } - acc?.let { upsert(it) } + accountHolder.let { + val account = fetchAccountFromHolder(accountHolder) + if (account != null) { + upsert(account) + } + } } } - override fun upsert(newAcc: Account) { - accounts[newAcc.handle] = newAcc + accounts[newAcc.handle] = buildAccountHolder(newAcc) persist() } override fun upsertAll(list: Collection) { list.forEach { - accounts[it.handle] = it + accounts[it.handle] = buildAccountHolder(it) } persist() } - override fun get(handle: String): Account? = accounts[handle] + override fun get(handle: String): Account? { + + val holder: AccountHolder? = accounts[handle] + + return fetchAccountFromHolder(holder) + } override fun delete(handle: String) { accounts.remove(handle) + + if (getDefaultAccount()?.handle.equals(handle)) { + persistDefault("") + } + persist() } - override fun all(): List = accounts.values.toList() + override fun all(): List = fetchAllAccounts() + + override fun setAsDefault(accountHandle: String) { + persistDefault(accountHandle) + } + + override fun getDefaultAccount(): Account? { + val accountHandle = prefs.getString(KEY_DEFAULT_ACCOUNT, "") ?: "" + val defaultAccountHolder = accounts[accountHandle] + if (defaultAccountHolder != null && defaultAccountHolder != AccountHolder.blank) { + return fetchAccountFromHolder(defaultAccountHolder) + } + else { + return null + } + } private fun persist() { prefs.edit() @@ -70,8 +116,71 @@ class SharedPrefsAccountStorage( .apply() } + private fun persistDefault(serializedAccountHolder: String) { + prefs.edit() + .putString(KEY_DEFAULT_ACCOUNT, serializedAccountHolder) + .apply() + } + companion object { private const val KEY_ACCOUNTS = "accounts" + private const val KEY_DEFAULT_ACCOUNT = "default_account" } + @Suppress("UnsafeCast") + private fun buildAccountHolder(account: Account): AccountHolder { + + val acc = when (account.type) { + AccountType.HDKeyPair -> (account as HDAccount).toJson() + AccountType.MetaIdentityManager -> (account as MetaIdentityAccount).toJson() + else -> throw IllegalArgumentException("Storage not supported AccountType ${account.type}") + } + + return AccountHolder(acc, account.type.toString()) + } + + private fun fetchAccountFromHolder(holder: AccountHolder?): Account? { + + return when (holder?.type) { + AccountType.HDKeyPair.toString() -> HDAccount.fromJson(holder.account) + AccountType.MetaIdentityManager.toString() -> MetaIdentityAccount.fromJson(holder.account) + else -> null + } + } + + private fun fetchAllAccounts() = accounts + .map { fetchAccountFromHolder(it.value) } + .filterNotNull() +} + + +/** + * Used to wrap any type of account before it is stored + */ +@Serializable +data class AccountHolder( + val account: String, + val type: String +) { + + /** + * serializes accountHolder + */ + fun toJson(pretty: Boolean = false): String = if (pretty) Json.indented.stringify(serializer(), this) else Json.stringify(serializer(), this) + + companion object { + + val blank = AccountHolder("", "") + + /** + * de-serializes accountHolder + */ + fun fromJson(serializedAccountHolder: String): AccountHolder { + if (serializedAccountHolder.isEmpty()) { + return blank + } + + return Json.parse(serializer(), serializedAccountHolder) + } + } } \ No newline at end of file diff --git a/sdk/src/main/java/me/uport/sdk/Configuration.kt b/sdk/src/main/java/me/uport/sdk/Configuration.kt new file mode 100644 index 00000000..de34fc4d --- /dev/null +++ b/sdk/src/main/java/me/uport/sdk/Configuration.kt @@ -0,0 +1,44 @@ +package me.uport.sdk + +import android.content.Context +import me.uport.sdk.core.EthNetwork +import me.uport.sdk.core.IFuelTokenProvider + +/** + * Encapsulates a configuration setup for the uPort SDK + */ +class Configuration { + + lateinit var applicationContext: Context + lateinit var fuelTokenProvider: IFuelTokenProvider + var network: EthNetwork? = null + + /** + * Allows the configuration of a callback that can assign a fuelToken to a device address. + * + * This functionality is being phased out. + */ + @Deprecated("This functionality is being phased out.") + @Suppress("unused") + fun setFuelTokenProvider(provider: IFuelTokenProvider): Configuration { + this.fuelTokenProvider = provider + return this + } + + /** + * Plugs the uPort SDK with an application context. + */ + fun setApplicationContext(context: Context): Configuration { + this.applicationContext = context.applicationContext + return this + } + + + /** + * Sets the default network to be used for Ethereum interactions + */ + fun setEthNetwork(network: EthNetwork) { + this.network = network + } + +} \ No newline at end of file diff --git a/sdk/src/main/java/me/uport/sdk/Transactions.kt b/sdk/src/main/java/me/uport/sdk/Transactions.kt index f2a6ea4d..a3e1d04a 100644 --- a/sdk/src/main/java/me/uport/sdk/Transactions.kt +++ b/sdk/src/main/java/me/uport/sdk/Transactions.kt @@ -1,9 +1,11 @@ +@file:Suppress("DEPRECATION") + package me.uport.sdk import android.content.Context -import com.uport.sdk.signer.Signer -import com.uport.sdk.signer.signRawTx import me.uport.sdk.core.Networks +import me.uport.sdk.signer.Signer +import me.uport.sdk.signer.signRawTx import me.uport.sdk.endpoints.Sensui import me.uport.sdk.extensions.waitForTransactionToMine import me.uport.sdk.identity.Account @@ -11,8 +13,10 @@ import me.uport.sdk.identity.AccountType import me.uport.sdk.identity.AccountType.Device import me.uport.sdk.identity.AccountType.IdentityManager import me.uport.sdk.identity.AccountType.KeyPair +import me.uport.sdk.identity.AccountType.HDKeyPair import me.uport.sdk.identity.AccountType.MetaIdentityManager import me.uport.sdk.identity.AccountType.Proxy +import me.uport.sdk.identity.MetaIdentityAccount import me.uport.sdk.jsonrpc.JsonRPC import me.uport.sdk.signer.MetaIdentitySigner import me.uport.sdk.signer.TxRelayHelper @@ -42,7 +46,7 @@ class Transactions( /** * A suspending function that takes in a [request] [Transaction] and constructs another [Transaction] * with the appropriate `from`, `nonce`, `gasLimit` and `gasPrice` - * according to the provided [signerType] and the [Account] object it's applied to. + * according to the provided [signerType] and the Account object it's applied to. * * Returns a modified [Transaction] object, ready to be signed and sent. */ @@ -53,7 +57,7 @@ class Transactions( var nonce = BigInteger.ZERO when (signerType) { - Device, KeyPair -> { + Device, KeyPair, HDKeyPair -> { from = Address(account.deviceAddress) nonce = rpcRelay.getTransactionCount(account.deviceAddress) } @@ -71,19 +75,19 @@ class Transactions( request.gasPrice != BigInteger.ZERO -> request.gasPrice relayPrice != BigInteger.ZERO -> relayPrice else -> DEFAULT_GAS_PRICE - } + } ?: DEFAULT_GAS_PRICE val gasLimit = when (request.gasLimit) { BigInteger.ZERO -> DEFAULT_GAS_LIMIT else -> request.gasLimit - } + } ?: DEFAULT_GAS_LIMIT return createTransactionWithDefaults( to = request.to, from = from, nonce = nonce, input = request.input, - value = request.value, + value = request.value ?: BigInteger.ZERO, gasPrice = gasPrice, gasLimit = gasLimit) } @@ -117,27 +121,15 @@ class Transactions( val txHash = when (signerType) { MetaIdentityManager -> { - val metaSigner = MetaIdentitySigner(relaySigner, account.publicAddress, account.identityManagerAddress) + @Suppress("UnsafeCast") + val metaAccount = account as MetaIdentityAccount + val metaSigner = MetaIdentitySigner(relaySigner, metaAccount.publicAddress, metaAccount.identityManagerAddress) signedEncodedTx = metaSigner.signRawTx(oldBundle.unsigned) relayMetaTransaction(signedEncodedTx) - - } - KeyPair -> { - signedEncodedTx = signer.signRawTx(oldBundle.unsigned) - relayRawTransaction(signedEncodedTx) } else -> { - - signedEncodedTx = relaySigner.signRawTx(oldBundle.unsigned) - - if (signerType != KeyPair) { - //fuel the device key? - val refuelTxHash = maybeRefuel(signedEncodedTx) - network.waitForTransactionToMine(refuelTxHash) - } - - //relay directly to RPC node + signedEncodedTx = signer.signRawTx(oldBundle.unsigned) relayRawTransaction(signedEncodedTx) } } @@ -161,18 +153,12 @@ class Transactions( .sendRawTransaction(signedEncodedTx.toHexString()) } + @Suppress("UnsafeCast") private suspend fun relayMetaTransaction(signedEncodedTx: ByteArray): String { - val network = Networks.get(account.network) - val tx = signedEncodedTx.toHexString() - return Sensui(network.faucetUrl, network.relayUrl) - .relayMetaTx(tx, network.name, account.fuelToken) - } - - private suspend fun maybeRefuel(signedEncodedTx: ByteArray): String { - val network = Networks.get(account.network) + val metaAccount = account as MetaIdentityAccount + val network = Networks.get(metaAccount.network) val tx = signedEncodedTx.toHexString() return Sensui(network.faucetUrl, network.relayUrl) - .maybeRefuel(tx, network.name, account.fuelToken) + .relayMetaTx(tx, network.name, metaAccount.fuelToken) } - } \ No newline at end of file diff --git a/sdk/src/main/java/me/uport/sdk/Uport.kt b/sdk/src/main/java/me/uport/sdk/Uport.kt index cec7aac3..01cc3f89 100644 --- a/sdk/src/main/java/me/uport/sdk/Uport.kt +++ b/sdk/src/main/java/me/uport/sdk/Uport.kt @@ -1,21 +1,16 @@ package me.uport.sdk import android.annotation.SuppressLint -import android.content.Context import android.content.Context.MODE_PRIVATE import android.content.SharedPreferences -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import me.uport.sdk.core.EthNetwork -import me.uport.sdk.core.IFuelTokenProvider import me.uport.sdk.core.Networks import me.uport.sdk.ethrdid.EthrDIDResolver -import me.uport.sdk.httpsdid.HttpsDIDResolver +import me.uport.sdk.httpsdid.WebDIDResolver import me.uport.sdk.identity.Account -import me.uport.sdk.identity.AccountCreator -import me.uport.sdk.identity.AccountCreatorCallback -import me.uport.sdk.identity.KPAccountCreator +import me.uport.sdk.identity.AccountType +import me.uport.sdk.identity.HDAccount +import me.uport.sdk.identity.HDAccountCreator import me.uport.sdk.jsonrpc.JsonRPC import me.uport.sdk.universaldid.UniversalDID import me.uport.sdk.uportdid.UportDIDResolver @@ -27,35 +22,24 @@ object Uport { private lateinit var config: Configuration + private lateinit var oldPrefs: SharedPreferences + private lateinit var prefs: SharedPreferences - private lateinit var accountCreator: AccountCreator + private lateinit var accountCreator: HDAccountCreator - private var defaultAccountHandle = "" + private lateinit var accountStorage: SharedPrefsAccountStorage - var defaultAccount: Account? - get() = accountStorage?.get(defaultAccountHandle) + @Suppress("UnsafeCast") + var defaultAccount: HDAccount? + get() = accountStorage.getDefaultAccount() as HDAccount? set(value) { - val newDefault = value?.copy(isDefault = true) - @Suppress("LiftReturnOrAssignment") - if (newDefault == null) { - accountStorage?.delete(defaultAccountHandle) - defaultAccountHandle = "" - } else { - val oldAccounts = accountStorage - ?.all() - ?.map { it.copy(isDefault = false) } - ?: emptyList() - accountStorage?.upsertAll(oldAccounts + newDefault) - defaultAccountHandle = newDefault.handle - } + accountStorage.setAsDefault(value?.handle ?: "") } - private var accountStorage: AccountStorage? = null - - private const val UPORT_CONFIG: String = "uport_sdk_prefs" + private const val OLD_UPORT_CONFIG: String = "uport_sdk_prefs" - private const val OLD_DEFAULT_ACCOUNT: String = "default_account" + private const val UPORT_CONFIG: String = "uport_sdk_prefs_new" /** * Initialize the Uport SDK. @@ -70,54 +54,34 @@ object Uport { val context = config.applicationContext - accountCreator = KPAccountCreator(context) + accountCreator = HDAccountCreator(context) + + oldPrefs = context.getSharedPreferences(OLD_UPORT_CONFIG, MODE_PRIVATE) prefs = context.getSharedPreferences(UPORT_CONFIG, MODE_PRIVATE) - accountStorage = SharedPrefsAccountStorage(prefs).apply { - this.all().forEach { - if (it.isDefault == true) { - defaultAccountHandle = it.handle - } - } - } + accountStorage = SharedPrefsAccountStorage(prefs) - prefs.getString(OLD_DEFAULT_ACCOUNT, "") - ?.let { Account.fromJson(it) } - ?.let { - accountStorage?.upsert(it.copy(isDefault = true)) - prefs.edit().remove(OLD_DEFAULT_ACCOUNT).apply() - } + UniversalDID.registerResolver( + UportDIDResolver( + JsonRPC( + configuration.network?.rpcUrl + ?: Networks.rinkeby.rpcUrl + ) + ) + ) - UniversalDID.registerResolver(UportDIDResolver(JsonRPC(Networks.rinkeby.rpcUrl))) - UniversalDID.registerResolver(EthrDIDResolver(JsonRPC(Networks.mainnet.rpcUrl))) - UniversalDID.registerResolver(HttpsDIDResolver()) + val ethrDidRpcUrl = configuration.network?.rpcUrl ?: Networks.mainnet.rpcUrl + val ethrDidRegistry = configuration.network?.ethrDidRegistry + ?: Networks.mainnet.ethrDidRegistry + UniversalDID.registerResolver(EthrDIDResolver(JsonRPC(ethrDidRpcUrl), ethrDidRegistry)) - //TODO: weak, make Configuration into a builder and actually make methods fail when not configured - initialized = true - } + UniversalDID.registerResolver(WebDIDResolver()) - /** - * Creates an account (the [defaultAccount]).. - * For v1 of this SDK, there's only one account supported. - * If an account has already been created, that one will be returned. - * If the process has already been started before, it will continue where it left off. - * The created account is saved as [defaultAccount] before calling back with the result - * - * To really create a new account, call [deleteAccount] first. - */ - @Suppress("TooGenericExceptionCaught") - @Deprecated("use the suspend variant of this method") - fun createAccount(network: EthNetwork, seedPhrase: String? = null, completion: AccountCreatorCallback) { - GlobalScope.launch { - try { - val account = createAccount(network.networkId, seedPhrase) - completion(null, account) - } catch (ex: Exception) { - completion(ex, Account.blank) - } + migrateAccounts(oldPrefs, accountStorage) - } + //TODO: weak, make Configuration into a builder and actually make methods fail when not configured + initialized = true } /** @@ -129,7 +93,7 @@ object Uport { * * To really create a new account, call [deleteAccount] first. */ - suspend fun createAccount(networkId: String, seedPhrase: String? = null): Account { + suspend fun createAccount(networkId: String, seedPhrase: String? = null): HDAccount { if (!initialized) { throw UportNotInitializedException() } @@ -139,19 +103,22 @@ object Uport { } else { accountCreator.importAccount(networkId, seedPhrase) } - accountStorage?.upsert(newAccount) + accountStorage.upsert(newAccount) + defaultAccount = defaultAccount ?: newAccount - val result = if (newAccount.handle == defaultAccount?.handle) { - defaultAccount ?: newAccount - } else { - newAccount - } - return result + + return newAccount } - fun getAccount(handle: String) = accountStorage?.get(handle) + /** + * Fetches the account based on the provided handle + */ + fun getAccount(handle: String) = accountStorage.get(handle) - fun allAccounts() = accountStorage?.all() ?: emptyList() + /** + * Fetches all saved accounts + */ + fun allAccounts() = accountStorage.all() fun deleteAccount(rootHandle: String) { if (!initialized) { @@ -166,21 +133,40 @@ object Uport { fun deleteAccount(acc: Account) = deleteAccount(acc.handle) - class Configuration { + internal fun migrateAccounts(oldPrefs: SharedPreferences, accountStorage: AccountStorage) { - lateinit var fuelTokenProvider: IFuelTokenProvider - lateinit var applicationContext: Context + //declare keys for the old account storage + val KEY_ACCOUNTS = "accounts" + val KEY_DEFAULT_ACCOUNT = "default_account" - @Suppress("unused") - fun setFuelTokenProvider(provider: IFuelTokenProvider): Configuration { - this.fuelTokenProvider = provider - return this + // only run when associated keys are available + if (!oldPrefs.contains(KEY_ACCOUNTS) || !oldPrefs.contains(KEY_DEFAULT_ACCOUNT)) { + return } - fun setApplicationContext(context: Context): Configuration { - this.applicationContext = context.applicationContext - return this - } + // convert all accounts to HDAccount and save in new account manager + oldPrefs.getStringSet(KEY_ACCOUNTS, emptySet()) + .orEmpty() + .forEach { serialized -> + val account = try { + HDAccount.fromJson(serialized) + } catch (ex: Exception) { + null + } + + account?.let { + val accountCopy = it.copy(type = AccountType.HDKeyPair) + accountStorage.upsert(accountCopy) + } + } + + // save old default account handle to new storage + accountStorage.setAsDefault(oldPrefs.getString(KEY_DEFAULT_ACCOUNT, "") ?: "") + // remove keys from the old prefs + oldPrefs.edit() + .remove(KEY_ACCOUNTS) + .remove(KEY_DEFAULT_ACCOUNT) + .apply() } } diff --git a/sdk/src/main/java/me/uport/sdk/UportNotInitializedException.kt b/sdk/src/main/java/me/uport/sdk/UportNotInitializedException.kt index e6689f49..3bc13a74 100644 --- a/sdk/src/main/java/me/uport/sdk/UportNotInitializedException.kt +++ b/sdk/src/main/java/me/uport/sdk/UportNotInitializedException.kt @@ -1,7 +1,7 @@ package me.uport.sdk /** - * Thrown by verious methods of the uPort SDK that need an initial configuration to be specified + * Thrown by various methods of the uPort SDK that need an initial configuration to be specified */ class UportNotInitializedException : RuntimeException( """ diff --git a/sdk/src/main/java/me/uport/sdk/extensions/TransactionExtensions.kt b/sdk/src/main/java/me/uport/sdk/extensions/TransactionExtensions.kt index 774c54ba..3f953309 100644 --- a/sdk/src/main/java/me/uport/sdk/extensions/TransactionExtensions.kt +++ b/sdk/src/main/java/me/uport/sdk/extensions/TransactionExtensions.kt @@ -1,11 +1,7 @@ package me.uport.sdk.extensions import android.content.Context -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* import me.uport.sdk.Transactions import me.uport.sdk.core.EthNetwork import me.uport.sdk.core.Networks @@ -20,7 +16,7 @@ import org.walleth.khex.prepend0xPrefix import java.math.BigInteger /** - * fetches the ETH balance of this [Account]s deviceAddress + * fetches the ETH balance of this Account's deviceAddress */ suspend fun Account.getBalance(): BigInteger { val network = Networks.get(this.network) @@ -51,7 +47,7 @@ suspend fun Account.send(context: Context, destinationAddress: String, value: Bi */ suspend fun Account.send(context: Context, contractAddress: String, data: ByteArray): String { val rawTransaction = createTransactionWithDefaults( - input = data.toList(), + input = data, to = Address(contractAddress), from = Address(this.publicAddress), value = BigInteger.ZERO diff --git a/sdk/src/main/java/me/uport/sdk/signer/MetaIdentitySigner.kt b/sdk/src/main/java/me/uport/sdk/signer/MetaIdentitySigner.kt index edf1476b..44bf161d 100644 --- a/sdk/src/main/java/me/uport/sdk/signer/MetaIdentitySigner.kt +++ b/sdk/src/main/java/me/uport/sdk/signer/MetaIdentitySigner.kt @@ -1,6 +1,7 @@ +@file:Suppress("DEPRECATION") + package me.uport.sdk.signer -import com.uport.sdk.signer.Signer import me.uport.sdk.MetaIdentityManager import org.kethereum.extensions.hexToBigInteger import org.kethereum.model.Address @@ -10,6 +11,10 @@ import pm.gnosis.model.Solidity import pm.gnosis.utils.hexToByteArray import java.math.BigInteger +/** + * A signer implementation that can wrap a transaction into a meta transaction + */ +@Deprecated("uPort meta transactions are no longer supported") class MetaIdentitySigner( private val wrappedSigner: TxRelaySigner, //this may become more generic private val proxyAddress: String, @@ -48,11 +53,11 @@ class MetaIdentitySigner( wrappedSigner.getAddress(), proxyAddress, finalDestination, - unsignedTx.value, - unsignedTx.input.toByteArray() + unsignedTx.value ?: BigInteger.ZERO, + unsignedTx.input ) - txCopy.input = newInput.hexToByteArray().toList() + txCopy.input = newInput.hexToByteArray() return wrappedSigner.signRawTx(txCopy, callback) } diff --git a/sdk/src/main/java/me/uport/sdk/signer/TxRelayHelper.kt b/sdk/src/main/java/me/uport/sdk/signer/TxRelayHelper.kt index 48ee92f8..fb13a2b5 100644 --- a/sdk/src/main/java/me/uport/sdk/signer/TxRelayHelper.kt +++ b/sdk/src/main/java/me/uport/sdk/signer/TxRelayHelper.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package me.uport.sdk.signer import me.uport.sdk.TxRelay @@ -9,6 +11,10 @@ import org.kethereum.model.SignatureData import pm.gnosis.model.Solidity import java.math.BigInteger +/** + * Helper class for wrapping a transaction for meta TX relay + */ +@Deprecated("uPort meta transactions are no longer supported") class TxRelayHelper(private val network: EthNetwork) { /** diff --git a/sdk/src/main/java/me/uport/sdk/signer/TxRelaySigner.kt b/sdk/src/main/java/me/uport/sdk/signer/TxRelaySigner.kt index be56c44e..2dc7df1b 100644 --- a/sdk/src/main/java/me/uport/sdk/signer/TxRelaySigner.kt +++ b/sdk/src/main/java/me/uport/sdk/signer/TxRelaySigner.kt @@ -1,6 +1,9 @@ +@file:Suppress("DEPRECATION") + package me.uport.sdk.signer -import com.uport.sdk.signer.Signer +import me.uport.sdk.DEFAULT_GAS_LIMIT +import me.uport.sdk.DEFAULT_GAS_PRICE import me.uport.sdk.core.EthNetwork import me.uport.sdk.signer.TxRelayHelper.Companion.ZERO_ADDRESS import org.kethereum.extensions.toBytesPadded @@ -17,6 +20,7 @@ import java.math.BigInteger /** * A [Signer] used to wrap transactions as calls to `relayMetaTx` function in a uport TxRelay contract */ +@Deprecated("uPort meta transactions are no longer supported") class TxRelaySigner(private val wrappedSigner: Signer, private val network: EthNetwork) : Signer { @@ -43,7 +47,7 @@ class TxRelaySigner(private val wrappedSigner: Signer, val nonce = unsignedTx.nonce ?: 0.toBigInteger() val to = unsignedTx.to ?: Address(ZERO_ADDRESS) - val data = unsignedTx.input.toByteArray() + val data = unsignedTx.input val sender = wrappedSigner.getAddress() // device address @@ -66,13 +70,13 @@ class TxRelaySigner(private val wrappedSigner: Signer, .hexToByteArray() val wrapperTx = createTransactionWithDefaults( - gasPrice = unsignedTx.gasPrice, - gasLimit = unsignedTx.gasLimit, + gasPrice = unsignedTx.gasPrice ?: DEFAULT_GAS_PRICE, + gasLimit = unsignedTx.gasLimit ?: DEFAULT_GAS_LIMIT, value = BigInteger.ZERO, to = Address(network.txRelayAddress), nonce = nonce, from = Address(sender), - input = rawMetaTxData.toList() + input = rawMetaTxData ) return@signETH callback(null, wrapperTx.encodeRLP()) @@ -83,7 +87,7 @@ class TxRelaySigner(private val wrappedSigner: Signer, companion object { //for the moment, the whitelist owner is all zeroes - private const val whitelistOwner: String = TxRelayHelper.ZERO_ADDRESS + private const val whitelistOwner: String = ZERO_ADDRESS } diff --git a/sdk/src/test/java/me/uport/sdk/AccountMigrationTests.kt b/sdk/src/test/java/me/uport/sdk/AccountMigrationTests.kt new file mode 100644 index 00000000..8f695c29 --- /dev/null +++ b/sdk/src/test/java/me/uport/sdk/AccountMigrationTests.kt @@ -0,0 +1,160 @@ +package me.uport.sdk + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isNull +import me.uport.sdk.fakes.InMemorySharedPrefs +import me.uport.sdk.identity.HDAccount +import org.junit.Before +import org.junit.Test + +class AccountMigrationTests { + + private val oldPrefs = InMemorySharedPrefs() + + private val KEY_ACCOUNTS = "accounts" + + private val KEY_DEFAULT_HANDLE = "default_account" + + @Before + fun run_before_every_test() { + + val oldAccSet = setOf( + """{ + "uportRoot": "0x1f9339e3c08c120b4ee05d2f500d57000170664d", + "devKey": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", + "network": "0x04", + "proxy": "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", + "manager": "", + "txRelay": "", + "fuelToken": "", + "signerType": "KeyPair", + "isDefault": false + }""".trimIndent(), + """{ + "uportRoot": "0x64d13f1dba46a91c85509c60d8a7fc72ea7fcb74", + "devKey": "0xc94b48237f776360d06d4acef743798fb5792c4d", + "network": "0x4", + "proxy": "0xc94b48237f776360d06d4acef743798fb5792c4d", + "manager": "", + "txRelay": "", + "fuelToken": "", + "signerType": "KeyPair", + "isDefault": true + }""".trimIndent(), + """{ + "uportRoot": "0xmyAccount", + "devKey": "device", + "network": "0x1", + "proxy": "0xpublic", + "manager": "", + "txRelay": "", + "fuelToken": "", + "signerType": "KeyPair", + "isDefault": false + }""".trimIndent(), + """{ + "uportRoot": "0xa17d3cd4a72b563076c12027d827ad319800fe18", + "devKey": "0x85ffef1627c80df773081a4967f27bbbb732a8ad", + "network": "0x4", + "proxy": "0x85ffef1627c80df773081a4967f27bbbb732a8ad", + "manager": "", + "txRelay": "", + "fuelToken": "", + "signerType": "KeyPair", + "isDefault": false + }""".trimIndent() + ) + + oldPrefs.edit() + .putStringSet(KEY_ACCOUNTS, oldAccSet) + .apply() + + oldPrefs.edit() + .putString(KEY_DEFAULT_HANDLE, "0x64d13f1dba46a91c85509c60d8a7fc72ea7fcb74") + .apply() + + } + + @Test + fun old_storage_has_data_new_storage_is_empty() { + + val accountSet = oldPrefs.getStringSet(KEY_ACCOUNTS, null) + assertThat(accountSet?.size).isEqualTo(4) + + val defaultAccountHandle = oldPrefs.getString(KEY_DEFAULT_HANDLE, "") + assertThat(defaultAccountHandle).isEqualTo("0x64d13f1dba46a91c85509c60d8a7fc72ea7fcb74") + + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + assertThat(storage.all().size).isEqualTo(0) + + assertThat(storage.getDefaultAccount()).isNull() + } + + @Test + fun old_storage_is_empty_after_migration() { + + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + Uport.migrateAccounts(oldPrefs, storage) + + val accountSet = oldPrefs.getStringSet(KEY_ACCOUNTS, null) + assertThat(accountSet?.size).isNull() + + val defaultAccountHandle = oldPrefs.getString(KEY_DEFAULT_HANDLE, "") + assertThat(defaultAccountHandle).isEqualTo("") + } + + @Test + fun new_storage_has_data_after_migration() { + + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + Uport.migrateAccounts(oldPrefs, storage) + + assertThat(storage.all().size).isEqualTo(4) + + assertThat(storage.getDefaultAccount()?.handle).isEqualTo("0x64d13f1dba46a91c85509c60d8a7fc72ea7fcb74") + } + + @Test + fun new_storage_has_correct_data_after_migration() { + + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + Uport.migrateAccounts(oldPrefs, storage) + + val account1 = HDAccount( + "0x1f9339e3c08c120b4ee05d2f500d57000170664d", + "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016", + "0x04", + "0x95979bb3ee68420a0b105f6e3c0d5d0fc0466016" + ) + + val account2 = HDAccount( + "0x64d13f1dba46a91c85509c60d8a7fc72ea7fcb74", + "0xc94b48237f776360d06d4acef743798fb5792c4d", + "0x4", + "0xc94b48237f776360d06d4acef743798fb5792c4d" + ) + + val account3 = HDAccount( + "0xmyAccount", + "device", + "0x1", + "0xpublic" + ) + + val account4 = HDAccount( + "0xa17d3cd4a72b563076c12027d827ad319800fe18", + "0x85ffef1627c80df773081a4967f27bbbb732a8ad", + "0x4", + "0x85ffef1627c80df773081a4967f27bbbb732a8ad" + ) + + assertThat(storage.all().contains(account1)) + + assertThat(storage.all().contains(account2)) + + assertThat(storage.all().contains(account3)) + + assertThat(storage.all().contains(account4)) + } +} \ No newline at end of file diff --git a/sdk/src/test/java/me/uport/sdk/AccountStorageTest.kt b/sdk/src/test/java/me/uport/sdk/AccountStorageTest.kt index 943ba379..c4c9c2ca 100644 --- a/sdk/src/test/java/me/uport/sdk/AccountStorageTest.kt +++ b/sdk/src/test/java/me/uport/sdk/AccountStorageTest.kt @@ -1,10 +1,10 @@ package me.uport.sdk import assertk.all -import assertk.assert +import assertk.assertThat import assertk.assertions.* import me.uport.sdk.fakes.InMemorySharedPrefs -import me.uport.sdk.identity.Account +import me.uport.sdk.identity.HDAccount import org.junit.Test class AccountStorageTest { @@ -12,9 +12,9 @@ class AccountStorageTest { @Test fun `can add and retrieve new account`() { val storage: AccountStorage = SharedPrefsAccountStorage(InMemorySharedPrefs()) - val newAcc = Account("0xnewaccount", "", "", "", "", "", "") + val newAcc = HDAccount("0xnewaccount", "", "", "") storage.upsert(newAcc) - assert(storage.get("0xnewaccount")).isEqualTo(newAcc) + assertThat(storage.get("0xnewaccount")).isEqualTo(newAcc) } @Test @@ -22,7 +22,7 @@ class AccountStorageTest { val storage: AccountStorage = SharedPrefsAccountStorage(InMemorySharedPrefs()) val accounts = (0..10).map { - Account("0x$it", "", "", "", "", "", "") + HDAccount("0x$it", "", "", "") }.map { storage.upsert(it) it @@ -30,57 +30,51 @@ class AccountStorageTest { val allAccounts = storage.all() - assert(allAccounts.containsAll(accounts)) + assertThat(allAccounts.containsAll(accounts)) } @Test fun `can delete account`() { val storage: AccountStorage = SharedPrefsAccountStorage(InMemorySharedPrefs()) - val refAccount = Account( + val refAccount = HDAccount( "0xmyAccount", "device", "0x1", - "0xpublic", - "", - "", - "" + "0xpublic" ) storage.upsert(refAccount) - assert(storage.get(refAccount.handle)).isEqualTo(refAccount) + assertThat(storage.get(refAccount.handle)).isEqualTo(refAccount) storage.delete(refAccount.handle) - assert(storage.get(refAccount.handle)).isNull() - assert(storage.all()).doesNotContain(refAccount) + assertThat(storage.get(refAccount.handle)).isNull() + assertThat(storage.all()).doesNotContain(refAccount) } @Test fun `can overwrite account`() { val storage: AccountStorage = SharedPrefsAccountStorage(InMemorySharedPrefs()) - val refAccount = Account( + val refAccount = HDAccount( "0xmyAccount", "device", "0x1", - "0xpublic", - "", - "", - "" + "0xpublic" ) storage.upsert(refAccount) - val newAccount = refAccount.copy(isDefault = true) + val newAccount = refAccount.copy(network = "0x4") storage.upsert(newAccount) - assert(storage.get(refAccount.handle)).all { + assertThat(storage.get(refAccount.handle)).all { isNotEqualTo(refAccount) isEqualTo(newAccount) } - assert(storage.all()).all { + assertThat(storage.all()).all { doesNotContain(refAccount) contains(newAccount) } @@ -91,14 +85,51 @@ class AccountStorageTest { val storage: AccountStorage = SharedPrefsAccountStorage(InMemorySharedPrefs()) val accounts = (0..10).map { - Account("0x$it", "", "", "", "", "", "") + HDAccount("0x$it", "", "", "") } storage.upsertAll(accounts) val allAccounts = storage.all() - assert(allAccounts.containsAll(accounts)) + assertThat(allAccounts.containsAll(accounts)) + } + + @Test + fun `can set default account`() { + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + + val acc = HDAccount( + "0xroot", + "0xdevice", + "0x1", + "0xpublic" + ) + + storage.upsert(acc) + + storage.setAsDefault(acc.handle) + + assertThat(storage.getDefaultAccount()).isEqualTo(acc) + } + + + @Test + fun `can save and fetch an account`() { + val storage = SharedPrefsAccountStorage(InMemorySharedPrefs()) + + val savedAcc = HDAccount( + "0xroot", + "0xdevice", + "0x1", + "0xpublic" + ) + + storage.upsert(savedAcc) + + val fetchedAcc = storage.get(savedAcc.handle) + + assertThat(savedAcc).isEqualTo(fetchedAcc) } } \ No newline at end of file diff --git a/sdk/src/test/java/me/uport/sdk/fakes/InMemoryAccountStorage.kt b/sdk/src/test/java/me/uport/sdk/fakes/InMemoryAccountStorage.kt deleted file mode 100644 index b4451b87..00000000 --- a/sdk/src/test/java/me/uport/sdk/fakes/InMemoryAccountStorage.kt +++ /dev/null @@ -1,30 +0,0 @@ -package me.uport.sdk.fakes - -import me.uport.sdk.AccountStorage -import me.uport.sdk.identity.Account - -/** - * volatile account storage, usable in tests - */ -class InMemoryAccountStorage : AccountStorage { - - private val accounts = mapOf().toMutableMap() - - override fun upsert(newAcc: Account) { - accounts[newAcc.handle] = newAcc - } - - override fun upsertAll(list: Collection) { - list.forEach { - accounts[it.handle] = it - } - } - - override fun get(handle: String): Account? = accounts[handle] - - override fun delete(handle: String) { - accounts.remove(handle) - } - - override fun all(): List = accounts.values.toList() -} \ No newline at end of file diff --git a/serialization/build.gradle b/serialization/build.gradle deleted file mode 100644 index 1b966c5d..00000000 --- a/serialization/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: "kotlin-android" -apply plugin: "kotlinx-serialization" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "tools for (de)serializing objects used by the uPort SDK" - -android { - compileSdkVersion compile_sdk_version - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - - api "com.squareup.moshi:moshi-kotlin:$moshi_version" - // kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" - api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialization_version" - api "com.squareup.moshi:moshi-adapters:$moshi_version" - testImplementation "junit:junit:$junit_version" -} \ No newline at end of file diff --git a/serialization/src/main/AndroidManifest.xml b/serialization/src/main/AndroidManifest.xml deleted file mode 100644 index 890aa64c..00000000 --- a/serialization/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/serialization/src/main/java/me/uport/sdk/serialization/MoshiExtensions.kt b/serialization/src/main/java/me/uport/sdk/serialization/MoshiExtensions.kt deleted file mode 100644 index 5076a94d..00000000 --- a/serialization/src/main/java/me/uport/sdk/serialization/MoshiExtensions.kt +++ /dev/null @@ -1,29 +0,0 @@ -package me.uport.sdk.serialization - -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Moshi -import com.squareup.moshi.Types -import java.lang.reflect.Type - -val moshi: Moshi - get() = MoshiProvider.default - -inline fun Moshi.listAdapter(elementType: Type = E::class.java): JsonAdapter> { - return adapter(listType(elementType)) -} - -inline fun Moshi.mapAdapter( - keyType: Type = K::class.java, - valueType: Type = V::class.java): JsonAdapter> { - return adapter(mapType(keyType, valueType)) -} - -inline fun listType(elementType: Type = E::class.java): Type { - return Types.newParameterizedType(List::class.java, elementType) -} - -inline fun mapType( - keyType: Type = K::class.java, - valueType: Type = V::class.java): Type { - return Types.newParameterizedType(Map::class.java, keyType, valueType) -} \ No newline at end of file diff --git a/serialization/src/main/java/me/uport/sdk/serialization/MoshiProvider.kt b/serialization/src/main/java/me/uport/sdk/serialization/MoshiProvider.kt deleted file mode 100644 index 66387e10..00000000 --- a/serialization/src/main/java/me/uport/sdk/serialization/MoshiProvider.kt +++ /dev/null @@ -1,13 +0,0 @@ -package me.uport.sdk.serialization - -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory - -class MoshiProvider { - - companion object { - val default: Moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - } -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index db22f4f3..d9dd4f93 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,17 +1,9 @@ include ':demoapp' -include ':https-did' -include ':serialization' -include ':core' -include ':signer' -include ':jsonrpc' -include ':jwt' -include ':uport-did' -include ':ethr-did' -include ':universal-did' +//include ':signer' include ':credentials' include ':transport' include ':identity' include ':sdk' -include ':fuelingservice' -include ':test-helpers' +// this module is deprecated +//include ':fuelingservice' \ No newline at end of file diff --git a/signer/build.gradle b/signer/build.gradle deleted file mode 100644 index 7f2f1f12..00000000 --- a/signer/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -apply plugin: "com.android.library" -apply plugin: "kotlin-android" -apply plugin: "com.github.dcendents.android-maven" -apply plugin: "com.jfrog.bintray" - -project.ext.description = "Signer abstractions including key management APIs that rely on AndroidKeyStore to protect keys at rest" - -android { - compileSdkVersion compile_sdk_version - buildToolsVersion build_tools_version - - - defaultConfig { - minSdkVersion min_sdk_version - targetSdkVersion target_sdk_version - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - testApplicationId "com.uport.sdk.signer.test" - // The following argument makes the Android Test Orchestrator run its - // "pm clear" command after each test invocation. This command ensures - // that the app"s state is completely cleared between tests. -// testInstrumentationRunnerArguments clearPackageData: "true" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } - - testOptions { - animationsDisabled = true -// execution "ANDROID_TEST_ORCHESTRATOR" - } - -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "com.android.support:appcompat-v7:$support_lib_version" - - api "com.github.walleth.kethereum:crypto:$kethereum_version" - api "com.github.walleth.kethereum:bip39:$kethereum_version" - api "com.github.walleth.kethereum:bip39_wordlist_en:$kethereum_version" - api project(":core") - - androidTestImplementation "com.android.support.test:runner:$test_runner_version" - androidTestImplementation "com.android.support.test:rules:$test_rules_version" -} diff --git a/signer/proguard-rules.pro b/signer/proguard-rules.pro deleted file mode 100644 index f1b42451..00000000 --- a/signer/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/signer/src/androidTest/AndroidManifest.xml b/signer/src/androidTest/AndroidManifest.xml deleted file mode 100644 index 8fec6256..00000000 --- a/signer/src/androidTest/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/CryptoUtilTest.kt b/signer/src/androidTest/java/com/uport/sdk/signer/CryptoUtilTest.kt deleted file mode 100644 index 575009a5..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/CryptoUtilTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer - -import android.content.Context -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import com.uport.sdk.signer.storage.CryptoUtil -import org.junit.Assert.assertArrayEquals -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.util.* - - -@RunWith(AndroidJUnit4::class) -class CryptoUtilTest { - - private lateinit var context: Context - - @Before - fun runBeforeEachTest() { - context = InstrumentationRegistry.getTargetContext() - } - - @Test - fun encryptBlobsOfDifferentSize() { - - val textSize = listOf(128, 256, 512, 1024, 2048, 4096, 13, 1234, 6123, 65535) - - textSize.forEach { - val blob = ByteArray(it) - Random().nextBytes(blob) - - try { - println("encrypting message of size $it") - val encBundle = CryptoUtil(context, "gigel").encrypt(blob) - println("encrypted message of size $it") - val decBlob = CryptoUtil(context, "gigel").decrypt(encBundle) - println("decrypted message of size $it") - assertArrayEquals(" failed to decrypt blob of size $it:", blob, decBlob) - } catch (ex: Exception) { - println("failed at message of size $it") - throw ex - } - } - - assertTrue(true) - } - -} diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/HDSignerTests.kt b/signer/src/androidTest/java/com/uport/sdk/signer/HDSignerTests.kt deleted file mode 100644 index 43849537..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/HDSignerTests.kt +++ /dev/null @@ -1,161 +0,0 @@ -package com.uport.sdk.signer - -import android.content.Context -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import com.uport.sdk.signer.encryption.KeyProtection.Level.SIMPLE -import com.uport.sdk.signer.testutil.ensureSeedIsImportedInTargetContext -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.junit.Assert.* -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.kethereum.bip32.toKey -import org.kethereum.bip39.model.MnemonicWords -import org.kethereum.bip39.toSeed -import org.kethereum.extensions.hexToBigInteger -import org.spongycastle.jce.provider.BouncyCastleProvider -import java.security.Security -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - - -@RunWith(AndroidJUnit4::class) -class HDSignerTests { - - init { - //Kethereum has some provider initialization code that is causing problems if that code is used before any hybrid encryption code - // the failure shows up as "java.lang.AssertionError: expected null, but was:" - //TODO: check back here when that is fixed: https://github.com/walleth/kethereum/issues/22 - Security.addProvider(BouncyCastleProvider()) - } - - private lateinit var context: Context - - @Before - fun runBeforeEachTest() { - context = InstrumentationRegistry.getTargetContext() - } - - @Test - fun testSeedCreationAndUsage() { - val latch = CountDownLatch(1) - - UportHDSigner().createHDSeed(context, SIMPLE) { err, rootAddress, pubKey -> - - assertNull(err) - - assertTrue(rootAddress.matches("^0x[0-9a-fA-F]+$".toRegex())) - - val pubKeyBytes = pubKey.decodeBase64() - assertEquals(65, pubKeyBytes.size) - - UportHDSigner().signJwtBundle(context, rootAddress, "m/0'", "hello".toBase64().padBase64(), "") { error, _ -> - assertNull(error) - latch.countDown() - } - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testSeedImport() { - val referenceSeedPhrase = "vessel ladder alter error federal sibling chat ability sun glass valve picture" - val referenceAddress = "0x794adde0672914159c1b77dd06d047904fe96ac8" - val referencePublicKey = "BFcWkA3uvBb9nSyJmk5rJgx69UtlGN0zwDiNx5TcVmENEUcvF2V26GYP9/3HNE/7vquemm45hDYEqr1/Nph9aIE=" - - val latch = CountDownLatch(1) - UportHDSigner().importHDSeed(context, SIMPLE, referenceSeedPhrase) { err, address, pubKey -> - - assertNull(err) - - assertEquals(referenceAddress, address) - - assertEquals(referencePublicKey, pubKey) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - //JWT signing something using a derived uPort Root - @Test - fun testJwtComponents() { - - val referenceSeed = MnemonicWords("vessel ladder alter error federal sibling chat ability sun glass valve picture").toSeed() - val referencePayload = "Hello, world!".toByteArray() - - val referencePrivateKey = "65fc670d9351cb87d1f56702fb56a7832ae2aab3427be944ab8c9f2a0ab87960".hexToBigInteger() - - val referenceR = "6bcd81446183af193ca4a172d5c5c26345903b24770d90b5d790f74a9dec1f68".hexToBigInteger() - val referenceS = "e2b85b3c92c9b4f3cf58de46e7997d8efb6e14b2e532d13dfa22ee02f3a43d5d".hexToBigInteger() - - val derivedRootExtendedKey = referenceSeed.toKey(UportHDSigner.UPORT_ROOT_DERIVATION_PATH) - - assertEquals(referencePrivateKey, derivedRootExtendedKey.keyPair.privateKey.key) - - val keyPair = derivedRootExtendedKey.keyPair - - val sigData = UportSigner().signJwt(referencePayload, keyPair) - - assertEquals(referenceR, sigData.r) - assertEquals(referenceS, sigData.s) - } - - - @Test - fun testSeedImportAndUsage() { - val referenceSeedPhrase = "vessel ladder alter error federal sibling chat ability sun glass valve picture" - val referenceRootAddress = ensureSeedIsImportedInTargetContext(referenceSeedPhrase) - val referenceSignature = "lnEso6Io2pJvlC6sWDLRkvxvpXqcUpZpvr4sdpHcTGA66Y1zher8KlrnWzQ2tt_lpxpx2YYdbfdtkfVmwjex2Q".decodeJose(28) - - val referencePayload = "Hello world".toBase64().padBase64() - - - val latch = CountDownLatch(1) - - UportHDSigner().signJwtBundle(context, referenceRootAddress, UportHDSigner.UPORT_ROOT_DERIVATION_PATH, referencePayload, "") { error, signature -> - assertNull(error) - assertEquals(referenceSignature, signature) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - - } - - @Test - fun checkShowSeed() { - val referenceSeedPhrase = "idle giraffe soldier dignity angle tiger false finish busy glow ramp frog" - val referenceRootAddress = ensureSeedIsImportedInTargetContext(referenceSeedPhrase) - - //check that retrieving it yields the same phrase - val latch = CountDownLatch(1) - UportHDSigner().showHDSeed(context, referenceRootAddress, "") { ex, phrase -> - assertNull(ex) - assertEquals(referenceSeedPhrase, phrase) - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testDeleteSeed() { - val tested = UportHDSigner() - - val referencePhrase = "vessel ladder alter error federal sibling chat ability sun glass valve picture" - val refRoot = ensureSeedIsImportedInTargetContext(referencePhrase) - - assertTrue(tested.allHDRoots(context).contains(refRoot)) - - tested.deleteSeed(context, refRoot) - - assertFalse(tested.allHDRoots(context).contains(refRoot)) - } - -} \ No newline at end of file diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/SignatureTests.kt b/signer/src/androidTest/java/com/uport/sdk/signer/SignatureTests.kt deleted file mode 100644 index cbe22ad8..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/SignatureTests.kt +++ /dev/null @@ -1,386 +0,0 @@ -package com.uport.sdk.signer - -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import com.uport.sdk.signer.encryption.KeyProtection -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test -import org.junit.runner.RunWith -import org.spongycastle.util.encoders.Hex -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -@RunWith(AndroidJUnit4::class) -class SignatureTests { - - @Test - fun testKeyImportAndUsageMulti() { - - val signer = UportSigner() - val context = InstrumentationRegistry.getTargetContext() - - val refJwtMessage = "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3NpZlEuZXlKcGMzTWlPaUl6TkhkcWMzaDNkbVIxWVc1dk4wNUdRemgxYWs1S2JrWnFZbUZqWjFsbFYwRTRiU0lzSW1saGRDSTZNVFE0TlRNeU1URXpNeXdpWTJ4aGFXMXpJanA3SW01aGJXVWlPaUpDYjJJaWZTd2laWGh3SWpveE5EZzFOREEzTlRNemZR" - val refTxData = "9oCFC6Q7dACDL+/YlJ4gaMziLeTh6A8Vy3HvQ1ogo7N8iA3gtrOnZAAAiQq83vASNFZ4kByAgA==" - - testData.forEach { - - val latch = CountDownLatch(2) - - val privKeyBytes = Hex.decode(it.privateKey) - val pubKeyBytes = Hex.decode(it.publicKey) - val refPublicKey = pubKeyBytes.toBase64().padBase64() - val refAddress = it.address.toLowerCase() - val refJwtSignature = it.jwtSig - val refSigV = it.txSig.v.toByte() - val refSigR = it.txSig.r - val refSigS = it.txSig.s - - signer.saveKey(context, KeyProtection.Level.SIMPLE, privKeyBytes) { err, address, pubKey -> - - assertNull(err) - - assertEquals(refAddress, address) - - assertEquals(refPublicKey, pubKey) - - UportSigner().signJwtBundle(context, address, refJwtMessage, "") { signerErr, sig -> - assertNull(signerErr) - assertEquals(refJwtSignature, sig.getJoseEncoded()) - latch.countDown() - } - - UportSigner().signTransaction(context, address, refTxData, "") { signerErr, sig -> - assertNull(signerErr) - assertEquals(refSigV, sig.v) - assertEquals(refSigR, sig.r.keyToBase64()) - assertEquals(refSigS, sig.s.keyToBase64()) - latch.countDown() - } - - } - - latch.await(20, TimeUnit.SECONDS) - } - - } - - data class SIG(val v: Int, val r: String, val s: String) - - data class Combo(val privateKey: String, val publicKey: String, val address: String, val jwtSig: String, val txSig: SIG) - - - private val testData = arrayOf( - - Combo("4e1559a4ec4dff8e2369635fc936fce9281d3044f49b8acaacd935041b6ae785", - "04971cbb0c73cc0a9c6d659a4eb772120f7c39bf7a9ecb69c1fc2af2a3088bf1e18d56aea43080dcc4b5153e587f9817951edbbba9f955c2fc56337338ca908aac", - "0xf34e6ddffedec32f759641552634f8b0df9c66a8", - "3Br7BEdZwSaX8wNBxBnJvDWDwlfjPhtP3LSR95J7p4QpZ_bhqXIIJIkZdU29a7F-A9CQRkTPVUGCWvGHJ2VUDA", - SIG(27, "TiyBsT+rragKtEbyeu5j0s3UBd1Mg1PhauWcz18FqR4=", "H636/N3+JGbF8Vl6z/CjasA5H1glEWD8JYD+UOT8zn0=")), - - Combo("25692381beee3b4e85f2acf66ada03b10672db2113f91f9df94e90cce5d5a1ad", - "04870a5b9ea009b4ad9eb2b40eb87c441bba3a14413fcf56d2ac4be5a954b39fec08368fa2e188fe6bc3c14cd14ed83e83de8d1e8475b3e3589a7d2718ae27cd73", - "0xa998c6074b5cc04fcd775303e0f9a61ca535f35e", - "2AqNpkt89PyW0mfg80sJZ5EpVVrVS88iAX-VvbWvJIhWXD3o45-9cDl_PxDJaRGYUMQXpNrji4dPLO2rQO8MJQ", - SIG(27, "PTsUW/G8/e0ABwXIVZA/XHM4JDDQfLSCst6+MY49IjY=", "IVxIsAt0Xn2Boc0j6V8uods+wZtH7LlwBbtpKQkVhfM=")), - - Combo("95b44703405c3a9a2dc24502d22681437390b6b5366548003a4cce8c0f0fe146", - "04a7b872b976fbae0798b00b0a32b24a4bf74068bb2c9c949f87816faac2112721794b334baba378ed46c834238a4443f23a4eeb15fba332af6424ef31a00d229d", - "0x7824fa28d444c250c0902fefd6c832fa88972db2", - "-wYyGYTgY_gSZGwwHg2pdu18qiqMtFh9x4nFPfCdaGhTb_GniZbo6GUb0xs1YvO0pO-fFuq4r5YUYcjbrAmbTA", - SIG(27, "Y61Qgg1DNwJj7dcdtdvnfpmiz+2URlBo+UIBxJV5Vrw=", "Ps4RL61fyom6akVXi65JaYeQnATMcKgrjmS5W8IKV3Q=")), - - Combo("efdd115c0ca8f5501ec03a2c4210343294956c898cd1fa4bae80d3ecc52b23db", - "042f578053fbb8b4dc587fa9a795bc60b5ba7d08e835f37f49cb34664cc32705f23577dfee6bb7d6a19d9998b373465bc7c0d9185d1d66770a74f53b1ff42297b7", - "0x8ac0e83a1b492bbdfd0da7a1048351a5b066249b", - "fcjKhN9m2HagKPb8fh5sMsldOt-GXt4GlfRiIDnhFIvOuWQVhVJyBbrkRbN8SmoeQ2mNkBhHm1PhT3DHWzEorA", - SIG(28, "y/u9o/qFhlFotjrSga+6MrTnilx+2kKGkV6f5SFAPUU=", "HTxXWcd+RgBLzBPTqulW9FbPFdZUarRSLyszyPRVTqM=")), - - Combo("6a5e632c21700b25a99b391ae4ef034e08a7a192914d38b4655dd9058fe498df", - "044b5d602119fe293fe75d89aceee3ad7623b159c61e0eb6837d52981ea143e363eb0604a09b62eefec9f29b14ef9d5199266773e5f316d34ede019c16357f75c3", - "0xfb643e22564cb6cfdf7677a610348c172b83bc7b", - "CxVQYUF_9radbcDNFCbg3142xZ6YRnlc3c6bVUX3diyzVmQzXL_gLdw-AeryZF3AyOlkf17TOXYS3pIXoW48TA", - SIG(28, "PzXkY4KKSA9UTquF5S6W+FzE9jKeIGOXdWoawhfDMHY=", "Xs7uQ5tp0djko4Hcq61SaEDYS+w2/HRuiuBNXw0ydBM=")), - - Combo("f93330497fe0d36e8e4fc39795ff8a82d5e4d388adb6c518c2582bfff2dae529", - "04d82922e10f15115acb74fe1a89c0de3d09d966906ef49225d510e858cb4e666c87803017b85fd33e3b98613e1494756c7b08011764a91ea16c793e384f2bff67", - "0x4ca3a9e0fd60bcfdd87681978bd6ab90e73b0832", - "-JaIQk8QIoUBSgLFpzPR0BLcN852zcB36zg4OKgSs_9lZXV-U5kK1GczXTihHhj8VoowdlSYj2HB58WKfD_uoA", - SIG(28, "fm0RDNglR2FHKTnsy8v/4M81hb6rOKNYt5LyGM59s4c=", "aCWKCCna/PaL0nUUCpeT+5LhGYd1bCyyZvjfVWu3sFU=")), - - Combo("01060240a4a4f38707482d9a5faf7fef6f9d5a93704598ed43759a4515a7004a", - "04aaf92ac70d5bb49ffd28eccdb85de6c7a4e6019f347ff8e1d5f083bcbff7e5815731801c4784d7846a3d1950f02822f4aa15466b126fd4d6ad3e360c92bd3ebb", - "0xf138e67af6783c1e29032dd095f9d836b05fe581", - "aLXtuFa1LsRV2JyPckvlEJRbPh2qTIlUVk2dRyIT2JnoV01tFO3MfaMn_uW8ahYW-9wiCemfA-4yJAUB6H93Pw", - SIG(28, "OFXjxx/u8tTA1w+Gjm4pPsIctT9kFHnqzcrJkG6Ms1g=", "YEkiGBhLXFUZrSBQYF79Es1Z0TIlitq5sCobTqc0kO8=")), - - Combo("4ee10f8179f853314ad5814f9c8a12aa78b5173c93ca7cdd1731740403f413ca", - "04d3d44f70a846825ab77db703e5d8924b5f6d723a98d2b0bd2dc9f67b6c4af2ce7d13eec8060df7d721baacced91c79afb7a439a56daf2f21d17ee45c5b9c4e6c", - "0x69ff45046756ddb98d61f392056b3d04e32d8bd4", - "mZspCm8ml4c0wP28H-mpZY0RQby42ZteHsvQ3osXObjGV8XckL_FzFY6leSnpiDF_iCCp390NSyEe7sfGeN3_Q", - SIG(27, "zz6scur+3rVrLuZGwnVRy91DemUva3TjizG6r9dkvWc=", "f4+JnvUpIwago5Zz+syugmdpfMhs4/OX9McQY21Qzbc=")), - - Combo("884c225a67e48935779f390db094818b7c2c0319f55c76cf62eb5b7a4df03f69", - "04d2d3498de5a3d0b5ce9e03c4858af7bc8a30a90ac245f11dadde36e4f5f7aaf9e550952a2b7d64f7ab5c8e0f0f6bcfb6a2a8f48929bf34c6bd0382ad48129fd9", - "0x674ba15dfd54b3e48f7134a246eb33a1202f31e3", - "BgFYvqekFZXmit58E6YyTOi7rkz9pXqY6B8Ly1lv-uA3eEAS-ajHbf5O3BHn8kKCTwRX7ObdZE_uACNn5k9-6w", - SIG(28, "tUPJ2LRIaP5vPMJnzMYgb7zLcq7y6wPT0wBTrTAJ0w0=", "ZyTMYjTyotr93l3LGjjaznINYjwnaB8KnLkg7ojogwk=")), - - Combo("019e0e384311b48e9ccc2750c0bd122e7e3b4db3d5c0a898b216068960f029fe", - "04f60f7491d3b9f99cabc62cf51779fcac00f808a8f04795ab70b4488f19d6802a286ad2a2684ef01b89d3a3b25b64234addd226984fbe8b0ace580e192c1b938d", - "0xcccbc15856de1c89fc7dd2199e0fd307619224bd", - "2_ddtzVB6tRanvkqWWdet7mzr8pf1kOXbAGvYAwS1O-jsE20rM8ezMQAyFEifoB5cObeyZagiphadDyjvFEaEg", - SIG(28, "7apUh9aRFngt95KDQCW/weJVN6IYWWUVsIGm+TRgoL8=", "fo97wNWLDcjWz6Uc9Lvh/lh9kuH6uPADGEw9o3oyKSQ=")), - - Combo("d003cd7071f4b3fe85256b4fa1046a1df20196b20b37869932dd28b9423e3f99", - "045887932f712696ceccffc18bf103d6b5b54ae7fcaa05af4e35cef958ba03083b486391e9c9408e470e95570bcb85fbb42f10b4bcc96e8f8d24f398a3f2050be5", - "0x2860b31d01c27ee58b65c9cfa96a66428452209d", - "DDN1d4Lk0-Bq1JKs90ToO6f7gw9u9K6m_fUvPT5ENvIIDm_6KI_M0FFSf02YS7-HOl1mvlHwGAyR-ommaCNpFA", - SIG(28, "Gdbyqii1oykpU9R2sbgLfdrnAauvQrbVDQvkkFhjiyU=", "e34dqk8rLKQYRKwuJKUzmPZiG9IS7lZbvhEc1kCiag8=")), - - Combo("20fe2194231bbbd237c94f3ffc55f4a94f536aa191b5cf026eb0d9ff20704371", - "041067a52549e14d563e572925419fe8dbb5a9b775aa25acc4ddf5b5b2d95d6e14951ea0e7fb0b915ac7d7c7fc00ff93016d393c80005a1820536c50774281e020", - "0x45e7dffad61bb58639de09d8e2f82af7a4b567ce", - "sqXseGUZDaoCtRC_IcO90b7zmeTMt9dvgNjx-vptsSg22b1EzS6N-DbaPEZk6z_oM2sEsWbnby-IX9JRI55zHw", - SIG(28, "MBCLYZlfUPVsW7Dtfa4UZ6zlamkXbFAGJJ536RjcWrk=", "Gq/v7/xJzDcszwq3EdRrhe8iJpnvgRmNXzuNFH6Xdsc=")), - - Combo("2fb2eb84a45c5a6b0f0a69c4868ce0d6deab7ae376cfc88f19b08f920746f69d", - "04ecdb8b1d8575eccf3d254c04a4ba0b9ec68c7a43053f5c3a37dcfccc0a0a4c46e4c579070e51807c661d13874fba3f50ddd95dd7289f99df4643a320ca7ce55b", - "0x034d9566428abf22fa1e48a61d6f0f5688108b60", - "CFEcsb0s0t8HMkD4hTYoqRdtAcoIgQk0cTIyD__-FQeh6NZuIciyc49e4EcNWxtXkocPc8aZCOKA2JTnbwAZDQ", - SIG(28, "fnMqglWNTqzdsHyxVM2Aq162m2Ps07Lf++nOmWB8utQ=", "X/I2oeIG/04RRqt1L6dnslOksnQdBafadI2YQ6J1Whk=")), - - Combo("fccc238b12e9c296c0f96d9e48a7dd3c0d4df195f53720d079728b8e1cc28b17", - "0438d034a52871836191ce5659eff157aaa7feed16c58bb8a2511c685a89779885e0a30dd52e56f4d90fb0282fcf67186d6f4f4097b8ec172853c148fda9b10178", - "0x51396c5f444b6ef5fc81733a7526d281c083d201", - "Y-5l1cPkJElpCS8N5tBMnlSGO4rCKS4L4-Wo0ei9Wvz5_2fER_lMApxm87ROv_hsxWpEeA3lUlgoI61f6kj14g", - SIG(27, "ddmKEBYryK+DW1NhBQcz3HHS6j2JcY50x2G8Ceaq92Q=", "BOzmcvwvX7eKWCjtZuu4ywP7jZ4pDo3FzopV4d+oRXQ=")), - - Combo("a7fec323144afe1c1773b38df6ba30604d86a85788855c0579fda0b1ab82404e", - "0473915692e411cd9c6b762a5653aec44655f9206c0d151b03d00e7a573e8838a849a702ef9174a537c01399989fd1bce95205f2677f2f39e892c0fa4ecb9e7209", - "0xdaa1c0545800dc929dea802d5dfda4023938671d", - "O3OPhOHNcHiqZ8lJQL9TsiO7zyOHU7Th3QZlnqtSAqFGglcDNGJJs0pTZBuybMt6tLohgGXCUiawcy68jvHOKA", - SIG(27, "jP5yS00LOJABy7lTMA7eUjIUYnzsIfGsrGNsOXMd4ps=", "dySgZteuxj3eD8WoBm0OEAf6WTtd8ETFkuvv03zsQic=")), - - Combo("19f99371c390cd8e70a0532c635e47e1355ceffda9c3bc8713d012ed03ec06e8", - "043ac91d6c11b62dd73b9d48fe2468be750e29200f7285a03752e8bc8bb234c42ef383bf61d08b75f9ce3aaef8a2fee39f86bd3cb4ad078c37249e04019e5937e9", - "0x2192896ae7d442b6f5b9b4eb2d62c68b64be9b7c", - "lIzyO31ZgS41CTBseyzFA7MKEqi_FIP2MJPg8wyuaVoPYvNwmPCbqTftfyYwv3DjDQKovys2-Wa6KiPiXs1ScA", - SIG(27, "WxmjC71w2NBzLLZ3ZzapeYWeHNCT66Y9oLISYmF+bkc=", "NIvLqlLrCptfmuQNtOy7k9ZUFPvcExi37JcxFog4F3U=")), - - Combo("62ce71798568e1f96495201a364e9670d399d97d8d5178398e3eb423dc0e7561", - "04ce7b781959ad7cccd5552251be811247654b212ebbf73b31802c8c8d81c0b79100963433ae5f5036e9a8192855284029c86070c9c70227181694f008ed7ec964", - "0x53dda7b3f76353a12c4330419edd002a40f6d264", - "SvfCtPcL_-i1760xXWP8AE8BEhEXvCTn6hbawf9kBIHIdiWiqz9uWoEobN5-3ma1Mjem7-zUgOvHV-qQ8ZbuVw", - SIG(27, "+IZ0+Qso0ZWPktRj9p8cXwM0vKfyy19AKl7tkayZ1uo=", "Pcs3AXdXOMh2Gv26qEbqFKkKjha8HPEbU/vjJTzvoro=")), - - Combo("e44c40c7728078ae6339101f81bf5302fc075011abd80ba09f32bd3ed2d06f56", - "04604b036899a9670804c382edb1566a2f9a9ba81165c6d820972e3fdcbefc69353b7254c6ab9860f519192bd1561c48d9df41b277b249841b59e79f308082f940", - "0x33e76ac20f2c2968736a511ab951ca5f1d3c91dc", - "OAjf7G2JK2j-KRjL8axKOaQL4sb3z_N2LvsaX7wZewqrkUL9arKTv2is1FF_gsi5yJkHbVjJcT6VwW-NfWRpTw", - SIG(28, "dTaLF/idookY+OnoJV1Fj+YXnY5sseAwI+x5FpK++kM=", "Wj+kSEUFcuXMoEWGjFcQy/mr+1R34XozhB7omduoOM0=")), - - Combo("a8baaee5cc9de9c05e5eca19f24ffb2a02702b6f31cb456138ad641a324b15f1", - "04a47d549e6a9ea697df7a2efff224d3829986f26502e4c5af8b7fcb0d9718f76a792f573d9bb628163321b3e09b848266553a1c4b8b8f6a99fecd2b24fcdc35cc", - "0xf10c10a877bf48cd6e165e598420d184d545c710", - "mXooezXiSupDRnkg04HMu4rxljwa7jnhEhDQPOr3QKacmygDhq0YUQWwyKViyrbhsyYNLQmrOfHe8CaERUhexg", - SIG(27, "b1ExJHRFB4pwCtINT3CdD6PF0BkmEI/6ikGOcgG9XXA=", "GpoZH+rSnNHovTM8T/QZoZunFfaxI93gTmELeEpwfu8=")), - - Combo("7f505ebd23dadd2a01e1115be61f4ccb4e6f12f09eb7e9188ee21288f456e577", - "04987c664b3e42d9582f59743af12252a1f741ad99a464d9129719477ba75b4673f1343e3de47cb41085a29b48ec71aa83cf85f7cfdd3eccee1b707acef1d983ca", - "0xedd67644082494a750f27cd88bbf1a71cf924c97", - "kgjSiYtYE3YymfKMiZywD_c_nMRHhiyL-gTpoNXsaq2nNFuueIiWRwAYY1X2ZHl8mBMr__Ume_mQT-MAvaQSyw", - SIG(27, "Y6lnfzUV7D+vpxLWvrfKOU6eF4ALX3sO+XOXs69Fg7I=", "fcrAhssiT3Byjk7EW0XzleA+UhgE14BrHqgehQY/PWg=")), - - Combo("ee97e7658fbfc07c5bfb57fc5a14f6f6c97d6ac8e3f341c999883175c20fcf05", - "04a238c1634624236c41f01c2299e6ccbbc257e6be213d97985427ca5ad241bbe7cae795f3f93319f28fa31f97cb92ba2999b50f431cf52e8e4d74530e73f811cb", - "0xacc258d24cf3bcce696970d82704b13651aa5110", - "gTskEAgYVe_pBEG2U9jA7U82gxIZLGxLV__m46KZO-fo-RIeEguk4kSeJft5MjuZXhyLkLxp3IDpihM8m99hwA", - SIG(27, "UiEf12c+nOx2qwIAC8u5wnw0czxcB/sPO215ZtypT+o=", "MWMQpHAKq39DsbEsB1AGb+hDnN1gE8bcC2fODjaI3k4=")), - - Combo("be9d4fb5c681f75c55243b81bdcbf30ecc2d7e1b8c7a34195fb9775ab76fc2ef", - "044e2bb08529f68c72cfd93710541c68e58abb2f2561dbb39a3275bda1e9720fec08f1c665524abd08a991832d3c7dc0639efeacd22e754c82fc59b2e2bbf42658", - "0x4c17ca8cc38ed5c6828085004d98dac7c1a88ca9", - "CcZq5_7Yv1UHJ_IkERzDL8hwDxZNd2hIAuQckvkuQWVFh9o8N4-aVxU5jLFGbMR4eNNhHwl4Q0PgeAads4sWOw", - SIG(28, "FNzxaQ9nZTnlZOjY0qymUvvLKhd8gy6lJuj7bwIkDFI=", "KM04QG5I0Rzqb5l9f7+sj6zbR/PuiubOBtTWEg2mD+A=")), - - Combo("3b0c49416d5ec9517e7870ab6566ac011da5ea5f011ddcff8e15d7cd0cd87328", - "042279e00a1c89b20abfc5b4af0efa96d36cf286eb36b5128c7d15aaa75be829349345412a5be6588dbab14fcc6aa107b36a2b92265dd8cb352b0dd806b1d772e3", - "0x5e120e24884dcd7f575a284ca3e9cbf9db70fd19", - "foeD4MInXaqrQFwFS8fu0e8Od-2wQ6YNRNAtHcmTg3YnOgXtwpZ9b50TskVdVh4B6ortcz2fenVHHET6Deo7-Q", - SIG(27, "O3UqbVGpe06GDrBM1KMO1Asci2hq0ucHN5MpzZHDuf0=", "GGdS5fvplCcWTuzfQZ4s4swJu9hztPZ5Jwzn+a5Uw9s=")), - - Combo("0565790c4d0915c167c089ddd63cdf3016f1651d97bd52541494cd7834e7a739", - "04e26735c1b919f375a69a3d0e3e1cd4ffcb9de7fb39811073afe6da03c6a2ceb01c0477fa6fbe5e54ee8242049128e61aed21bb7b9edb0a7c224833741837f0fe", - "0xf087ac18893f337cc6c4f3392ac02cf36ed29b21", - "6vqOMUbEvEohSHucATLZOClqtR5XbfSVAvcO77ryoezGHKA51TtYAwFuP-CYjIBiCrN2BqiDCat9BEYpW-WoLg", - SIG(27, "F488AWPD4srfimiaF6oecFfrwSAXwRIMbDNBDapFrVg=", "M/ntFoU/vhfLNFGrZUhFwd+WJ+AQvlA27mM4tVqVdYo=")), - - Combo("c8da839ad57a613d97c5e374d621f70b7b78902492da70f3ac271fe27d5652f2", - "045b3c5e611ea34896e1e07a4f664da6b9e4352be568d9d576b93800611ccdee7f4bc16fc3b936c35668cd70c77b894daee1100795826fbfae7c977dfe9bf5724f", - "0x7ba6f7ec98a081e00a4b4ea6d4608600a2140860", - "UVWK8Fj0_UCYOX5k054VDieDqjNyMEDqU9z7sR1pBlEkcnNHSPTy-_yERivs256JF6agLvUpkbEft8bM9SWRTA", - SIG(27, "2+F4WypEy/QLatF3sBW4zmVWadB3g5P5f0h5UeGK/Fk=", "H1I+N1/X3BvirIHDhSaCDcgwsu9nX7YjEY23bhdrUOk=")), - - Combo("c995eab5513262c2822e15920b9064376d1b33f01b125e0d7093e7351e366d5e", - "04ddc5215b73096ce8bd6ba48dcbd0ca527947bb89c6299df393c6730cee0a508eca50fc5607f76ad66bfd596a04e88faf178c456cdfae168beaa8b3e2bec86dc5", - "0x5a9d02fccee8b2507820889c6a25907592b2352e", - "UMku-ulQQMyhJIsKfyTxIEe7_HV5k7IApDl8VtuPnnktbmoqFVdIbMNFarr15GYt-IoA125oQLP9Bo23OU_q6g", - SIG(27, "cKUwmDelHTcpZCc2FSJJowKrRDYpFNtSSqL2k46VH0I=", "P3E8AWzHcUeu8nXmBlzaJIomWtuIZc3OVM9qmxUJOSE=")), - - Combo("f0176976a08750d2ad33eb46f339511b1f23990c2b5a8c59574fa75bb3bc9aad", - "04cefcc25039c8da1b4da310e143c82559fdcfc06bddf7ba0469a5207d2dbcdd35be69fe57c4ea2f6a923931b9a1b44ed65e1d9f0401ea63e662a6f7bc6c94416f", - "0x94c43da2c7fb4986925ce2a3cc2adb4be42457de", - "CTlw7KDH6Pwt1mAeNbR1ePaQ06dv96NreO5Es7b4L8L4TP31vsupZWsiBSeOQ6m71TapkgyTOgpavNXF1wbYAA", - SIG(28, "1GOzHHHiQZIkHCp++E5VDQ+gfpxHFv5YtIkclkhUH4c=", "Xqd+ptV9/QpoHv8Z/ir5mVCscBYWvJEe/E4AS9nUE/E=")), - - Combo("313bc6445765165aca25f412475f3321842c270d9400f585d59bb8ed23167c1e", - "04e21b6775c41f568f3d46829a5b3844044231ba26a77fb42c831635095e9f08c09ce4980230a8937e9f22711a766c2a8c88e420b78b0fe858505661a418664f0c", - "0xd07eb4161cd20716e7756d37d6ac0d2e851ea3dd", - "vQTFP2H24XMthwRsd80Hxh_7GnaGeLAGWSUw0pEz3SfSaYbtdGUOefXEsdEBrvYXVSseQQr1VIGUc_hZ8j6rPA", - SIG(28, "yAPxN8j8o/poHX/TTgIxm9GgWRCdX+D507w2nDWGyfQ=", "fBXdhRO6X2wRJVIv9cbwlFgFk22Xh2V+znOCjMb8nCI=")), - - Combo("035d88da05943288a90581ddca5a3dacb068beb60602efa26ab61f91b202b098", - "04234aa244803d0c6daba8361bb6ea5225947ed48508958667cc17507445adf9377a605e9866bdfc5b59b8339c9577491655a77a09c8be0136e4b9d28098a91625", - "0x47221e33c828259edbebf4cde1e57bf09224fe7b", - "npBfIb-pGeG_JrEXjmDJrBWMa7SroSoPBqbAsuHC-yZjFFOBNuhoOc6nAJzRvtoGRH_oT7LXz_bqdoIVb2KglA", - SIG(28, "4AOp+h/WWIYUyClst0ypx3yosxTFUvhQ11Cs95AomQg=", "PbGvvjxw1H8GwumAKXjXcnIuz6U35scAa1WG/e9OTbI=")), - - Combo("c5f42cd60790e3d57f883a535f19902ee9515cf2f5e3031767499116e5ef0835", - "04afa6e4ee3ecd820bf8442fb381513e4fffa1f94e3268db8fb9168fc963289f63541549d000fd26dbf9d339819a3b1f6496c7592e22c6c2109439614fbe7792ed", - "0xc7f2b6ce3c775d0e011c77a978ea1713c17e314e", - "1s6QCrFtWOghTRreZqimcJGqLob3dYq-fPOV7YBu4DmPiGdOZeF7aVOVh2mnPiKChdCWyws71t8Q4kcbn4KOvQ", - SIG(28, "DxPStY6FhR1cMnrOY2355mtwz7Tbe2mUkToxL4zW+1I=", "dgfh0dhqPM+QyeTg8TRx/o99YLQFloppP7IKs6dl5Io=")), - - Combo("18dc8bd93b827cdb2c03555ea1c25f641c14ca9e309aa4cc06c8c8a27682dbe1", - "0418010d32c772db246f362308d871c10d8a329501ae099583259d3427514462a70a6f9b7d6882451dc823e577658100db4a70758e8cb3277a7fd8ce34da4dc11e", - "0x8183a72d9163f19400bf4243de3d2307e42044d8", - "2S3X-IburN8P5uuaDuZkLs4KpMKkxhF3a20mtV1NJ0Q1liWt1h5x4zw9owN9clYpor5jBZgYAua9Gl7neaTkyA", - SIG(28, "K9/Xqq7SdUJsrAo9hJR7T9vNvztkIPTxG3VeNNmqtFQ=", "aEYoLqpdqpdp5+RWcdB4k7nkpQrlXHVfRydH4NcJbQY=")), - - Combo("3dd60ce7a16cee8844304a3008e344a48802040f89aa37b5a8c644b3e03734a8", - "04ab052bbe671c5f09b6b2edbe9326170758d83e8344caa3fd3a10e59d294bd66ac4ddca10823a265a4315d97147eaa9768c28fc87ae50b3c23ebefc9b78eeb671", - "0x64ed433519e8c99c990104e5feecca360e88ad67", - "OQQuRn2m5NFVgm7OVL9amcr1rvfuOe6dv9ojul-PGOLWbqS5N_sFiiSbckrZXBElWcYe9NR6iULMEfFJ_aP0rQ", - SIG(27, "AnueK0BcFhcUZPLePAPyWQzWbkOX0TRjp9SYu+cWeD8=", "LASEGyUukne5fc5dL1w+CX9aiDC5YUt+3oKsg5tGAEU=")), - - Combo("a0670660819203cc4cd606fb10e41964c88df593f10a7b3a6586a0c77cd7b788", - "04a325ab40e5abacf3421551cd04e3fe67c30a6bd9b20ccfc928bca5c641b0f18cf41b0bbbebde829c67b355327ded5e767ef8d9004efc70162cc172a7a9431c48", - "0x8da5e4f050638e59e87bba9ecd2cb1e6daac777a", - "NfR8hmJDpwTjq0zUl4hql2t69AwiMXFSiA6jxDzoa4wLX-5o957Cryw0hUuX9qAqtw8AbMCvVJCiYe7LId3NqQ", - SIG(27, "z0l0N5ABmZwQwSMhHh4HhZoQF1Ngur2dAnghEFHYJ44=", "AVfJYls7Wc/cKBlIs9jItTfTZbHFEdcqLvTRX5vLT0w=")), - - Combo("4058c4d945d175894a343593e20a7ea0e443bc7519f6e724cbfdff33caa1c417", - "0407770f4cca19f7f2c066d9278caa6d40b89e32251e696b9ee24753a151589bd9b131f995a8938bbbc8339b56e2880772410db55b055365243d6adb5ca5ea7b16", - "0x0e899ed45a65b7df769409ad7b4022a88ba6e88d", - "i5H24fGipgB3uqKFybinTShghtVWXSDzLZgC7xv-OtDkkakkHXL0z-9zYv6CultHF4H7AokfR2jm-XEojVi9vQ", - SIG(28, "4fpmukGxYAFV1kH3yofvQgrqwFSUHrTVehEQMPDkzJI=", "Y8aS+SbZF+fBeA01jFPX58PsfoKaCQ8cy4csp0FyJLs=")), - - Combo("28f92893986f228df0701b671797de98692dbea624e9020ae90ca46324f1dbb8", - "0430f6f8205a476aff0be8a5822039bc636010f60ae550888901309061b2dcfbb8ab8570849d58c5c26fb0a2e21164dcd9cf7dd38346c30ea319b4d85e173fb648", - "0x2cfdba50cef4740afb6653637b9753e157013ab9", - "iOYwRCk49OhKhfpE9ToUdSnhnsT7kW9yJeQ6q-qN7kO8AkKh5_HvoJBnSem6Ttqls8kEjF-mcyTyBtvkTwJR6Q", - SIG(28, "W5+3rQKKjRGS9r+pooK5e7UULDM6JV13yAeP9bvj8/w=", "QD8LIj2DzGMDKX5NYPvd4H4PeIHxRGr2JnZX9zLKRP4=")), - - Combo("538c6cf52b02f0197b3ab5ee0c4daf22d10d9e0481949bc9918216e89b17004b", - "041bf5f17e55a2c873e8ef8a69bbc32b1cc01def543460c246d89ad91d193042493a8fa619200f35bf7e1babe67dc893d75921f4734e3a3d9bbc02517f1056a31f", - "0xc7567e2839190e618979a2e0ccd29a1b661b0901", - "-cyEBJEWjUYabyTJNi6rn7sDCIniKtlftxxoQmyuJEUE47o3nMAgfFALLoEH0NF1VuzzLyPoQmaRdrp5iZjrJg", - SIG(28, "C4/aYMZuqJr10ChbxMPEkBfrRXqJ8dl7ic7p/0zssdY=", "BVFnSn8gVpJXOoHFmWiYv6chvuRQkTbyR84OpbwRBgQ=")), - - Combo("5ec82d04429686c9808db35b85d3a84db754f58bc46e0499dafefac308bc0a69", - "04aee714af6eb30f96a1c256bce9b6313134adfd1144f986d1959c2e04a0abb1f7942ffed5f27d4d2cc7ff833822da038c7440163956be4313622aa1a1ab5e73f2", - "0xf8484190e003797a21eb2b522b0e7f3545bc5c98", - "_-evI1296bUxUinbixLgfim-27QrMDo1HCOwmJd1cOH0Q2BL31F0mx--3rDvK9xbz3kIPNGGUBXhial_MnPxdw", - SIG(28, "kzy2H/0+/UOyyuotaz2Xti4kwkqJHbvpag+0nhGYCTg=", "CYvCL4+NuPSbWP5FulA6FM7MXsdbICN+E8PUiNPPukw=")), - - Combo("25f904bda7cf7d8ae422a3dc0a8b8b838714064deac36d0481f8e999d3b06318", - "04e4fa81dcafb3c23a138082fda1101e050377e68d129f333aef77d47920aae3e6e7fc7ece4a342f97bce3e3827c3c3d7e15d623286a4e91e814d40e730212277a", - "0xe694d6bfb0e0f60e047f37790f0bbf2e3a78352c", - "otDw4UATSRxEQl45M16cHez3AEIm4Vz_QZg8uy5zddqRO2kX49M8enr3yjsLVuRkE0cqH4W6nfu4tSRJb847kg", - SIG(27, "kK6qJ3rfp1JTOBllEmHziyPyPzaDScu/UqYpLbaIwzs=", "HqABQoNLa5aF6sppmPWuoKFrPQttMaRlsKx5j5JQ2mI=")), - - Combo("b3d9a71fcf70440e851e303e13851a89b35a5f37911d57ba0fb88627279f21a5", - "04bd4bd6c081183df296568823e08a08cac67fc8d3a451b3d2a52b06835e0b93b413d4a4e72d0edc846641296e91685683ab5c6fe7206e79581afe598f8c8eee80", - "0x769952b356819d8e1ab63312d5ac3c2c14d1801e", - "xWUEZjxun0i2DpZ49uJKSlCAkZw_bkGRbU-PElF4r_0I0dP6DAJa_dd_c0VLmyZadeKNaaCssi4bJNnTY4vlDg", - SIG(28, "i+t2rOwZGZiaooevO9ftIo+gQqjRPsyE4G7sc1x5jrI=", "fIxfJr0+rNzGrJOKCzX5o6/ohjYoC6DqORpoqVfI8h8=")), - - Combo("c87645ab6c562e4eccb6637a70750bb79e751ea68910b1dcbc49d6ccab721e2b", - "04b33a561ed4be3f832a07d7073933e1e108e31a3b1ed6942d918c63bdd5783a14a8228e04ea37b42cce8f17c63611bc1edfc820bf19166094c63c7da0bc0f24b2", - "0x4edd332bd5aabc51a7305f8c0b6220a3ce438c83", - "Rknuj10koIStG1Yj7ePzsaM3LIUlECK1O_oW3CsMbbHwfUK5LemfliZBGHAsyY-l_IeTRVucwlldc-W59Xui3w", - SIG(27, "zQaCs3ADBkU21CHa1R1a8e55wI2E6m5Kk5zmMZI9Jm0=", "WaF9VnW7dHPlpvXCus0/q2yASg/KxXN/SgsiAQdL6RQ=")), - - Combo("c69522947b9a0e9ee3151d207ce4c8273f14e2862f8957d128f4a54e7248e31c", - "044eb40819ad5c62f1791058d66402956e09e534bec8879c9b7c9fc5ba37874af8308f7b6b4d4bed395d50a7893cd040214b8febf6c6cefe69ac95b570f5cc8ffe", - "0x2a5c2ae9941f4cedb047289e2b9f3357b16baa0c", - "5JAjO5oKXaZUkQ8Ae6SmyVTP4lIBm4k2KNnzcwfbhylXzC6PbrX2aPm6YfaTU0ZyghMFLFOw6ElOMuOmMH3jsw", - SIG(27, "fKWGAz9Muzz0p/2WQywx2wWaK6lAXAnQrsdYLqVScNQ=", "QEHoyPgUb1u9u9oqQcc9l5eKBjB6YHFFmsXv/TCe68s=")), - - Combo("221c52e66ac846058181aea5e1d6379c4daa39887c744e03e0c1bf6b893f4375", - "04807b83b8dcd5868465d67efa75bed4264f20cbef57380d76a9ff501cb42f5655a98287cc5b7f8597473b53e168f72f6157220bdf7c99bcaec39de30bf5df79a5", - "0x44ab6c23c05f227447196356d7a8ba8f5f5ccfd0", - "q9X7DkW2nNxhBUDhb8h-wfQ8yDEu49WZjvQbeHCusPPSVGc6IeRiDIgPyAuqjQ7TheNVQwXfjDYZNn34MIZx-w", - SIG(27, "3Hl4C5z9aHWeqzmFoB4RqEslaaTAzNfFbjKVoV2POqA=", "KCrNtGK7Xv0DsNgAsJjrI+GVsMGlbfrAufCEMbx8Z5I=")), - - Combo("0b6bf54bec26d47b5313e725a3dd9fd39162d64b37d6fd773b0e789bd33b8b0d", - "0495fd48c4702c7e0e813663147d9d8ee255ceb18f657f7777371ba50a7048a7f082f73d2461b7de2f7c15cb6330d8fd15f937500ac32bcbdb313b59436f183a4e", - "0xfcaee7e3d0786365eb2917d3bb1fa6392444387a", - "w1V0LeVBDhTC5nOB65a8SJzM5_Z5_jJkJZZVE0G64RPLIE1SYCSeF2wFDBNmSHZBAX5MQPMyjV3POkNVLvfs5g", - SIG(27, "JRXIRog2SYeudMIllMCDtxZ28kTeNGYPGAuVt9ccxaM=", "IcA+VeL5NK6BuIvf/hwyXADWKzzTf0iQl/IoGFWzjo0=")), - - Combo("17c7465cd05dba8fea7045cba4ec344f1bfc2b03cdc6927dfeced97126a84f82", - "04b076bd9254aa310c885b770fc077c454f43e81669fe7666851909253b1710ad3059bb480cef5426ab8ec69cb7bba3c3ee625cf94b3d0c13156363e427d24f262", - "0xde3700766d266524bfb1bc0d8d5e077fb6f65a42", - "lqSEFF-Mv3uQhB-Swx9yRgK1Cp5V77LLTKi9b9-opZpCOsapzjH8GzMgNnNUEJcO-EvF40_hlxzWykz3pm4qHQ", - SIG(28, "3DjCVrKJgwtFyUHRrondYjk23bDjEgqJAR+BHIDYM48=", "VzQzMEpyO5yXgwwFB1oFG1vTFNp/OMdT66iuQ1UNScg=")), - - Combo("72255262378a076f766cd17ff015174df23f5c532a937c9bc03aa5b4e9afead8", - "040bdd7d98b734dbd6247c67a837b33ee74401c4c38201437262d0c7fdfc111c01405916defec76762e51a50c4b09fe351b1a93ac3611b1d4c7ecff4f480b70d28", - "0xc92a4bbb46f48fed7cd154a71afa755732e460eb", - "wzCVKbqYbNmeyFNN86TrlLESCh8q4pUZl7FqaW38DY50a3J_N7_1QVUrUTO6Nof-cpfl3gR3KqBz4ejTHWBCEg", - SIG(28, "YBDkYIYyOe8ynqdqsmIZUFpGctcrufMeNQgLFjvLZyE=", "Ys1iqiBu2lEHbDbn92xxLfWPDu7XyShtUyGXqgAD5Qw=")), - - Combo("92465e3f17be18e01509254a10dff6ddf18d8651e091f3a045332cf896dda240", - "0416e6e2cb9628899517eccde44441a051d16453d4e3c3bf89286f2fc8d14b63566af4ce44a519102691fa5382d11f64bda3ba44f5046875273cb1e75a4e756bb7", - "0xb8489af2cb572304c607f14c991efa83517da888", - "Y03oDOsmltbseap8QuIUFM_lDzu2o7QolEXxwV5tlArlhxO9mAzcLSM7zJKYz0L74cPZoQiMiZaeKM1ohYgz0Q", - SIG(27, "WW5ASMv5cMrXo94I2nqOAHDT6yArkG4+Zi9/VX76JGQ=", "OWwuNMQ/nknmfcYBxsQIpLfPdX/SwO/RhZZkFVlRLvs=")), - - Combo("73391c9fbb1b79f7a53614a2ac13058bf08e62d299fe0afb48337be4f98d33ab", - "04fc5f09a8fc15e19a813883b1c2aeee1931b560d3490c31409aa64f7bff5176a42805f02cfdd4758e065bd4d47181b9d08109f6254fa4aa8f785ed8f0d7ae3234", - "0xe398a7b24b6931ff34b557ae14db3117dd51fbc7", - "2WH02NgmsZgPawIKXTLsz99JqTiyrQ2FXsNJBwyMNkQ3_XTK-tqc6BMU3XP2mg2CXs2RHEZSwn1GnJfP1VOomQ", - SIG(27, "MDcNPEbo2UzVJeah0IVnp+CEJirkrdfQ2Xad2Ca3SQw=", "N2K+BWZEDC8V76w1HnnL6GFKqHW3vRtUf+wyrdesDsE=")), - - Combo("d602f2d7c4845a7b64fede9c79eb7367661e2299b877457cf957095c38ab1d9f", - "0428fee3f420827ca6f6918d2781e84159b0e8255870465e6095ee382e3d51e44a0780bac78b0d0862fd0911bc3c0efc826e015ff596beda60a55aa5588d7d9731", - "0xd972ed893a96444bd27ac6e21d8de4f12608e4d4", - "ZwnD-zdlXtmclgb4kxwrHjghiu_RiNAhvpcMtBg4dD2Tif60MCeg7Gf0LVbhnt-MWoHXDD0BKKqurawzAaTV0w", - SIG(28, "x/Wa9zE1gEgHBceTTjoNHkGMXl+jzavoHWf/T9N5tIw=", "fq8vzjGLlcPjZmX47uoom6jqethXVDzgPfE9/vISXAc=")), - - Combo("1e029460a97d52117f66b09e25d69eaf0a03cceefd160c089ef067b6708d014b", - "04ab498637325d94e623ee92976281635706c8d92548d38617031a38f06fdebc769fc2044c24d5741765af76cc5740996238e06e6dfc80f839639c325d0fe2ac4d", - "0x30fde40c45959274e8da4f16e641936c492fce2f", - "090Wgb_MnL1Ei5ZYwJBYTZtKx4KV2wN7Ar1r-jIl2gMWpiRgC3TztCQbxlrukAmvq9XyEmbnn8NaVDpDDEkZSQ", - SIG(27, "BYeNaKRco0ngGgdpn8rHxpDtLEN4ZPoCisYfp1aFIZw=", "QgJuTHJASMS3eRS/9Wh3wrdZrSxr+eZ7ZS4mr88It2U=")), - - Combo("5499ea955c098840775cd627ea4fc93d8f3de17f8721a93be3ebe3b7b70b4fcc", - "046ec4a7100970431fd24200a7187b3a92ccb7ea4d8a9de36fe8952a37c2c2f77be895e730043ee2068f4632dc1dd1e04a53f23bcc3e02f562f21645097906c346", - "0xd4318fab9656eb478b63caf458262ca95e914e78", - "yj3ebIZQQpX_TmZeKUxSzAmUib9PAAmI8DdshnrVpLDAY3eYb6rFnDtUgMf7Unz0ALXUfqvc0JFNKNDJK_WwXw", - SIG(28, "N3CIZNI0Cbma3HvyFwNjj+wTlt3FdMHqEgTkPJxjC+c=", "CiDhJ1ZOvJVdMsW98Z03EcNFlr/eecOBUsgmcIC5wDM=")), - - Combo("818b285cf19c5fbd3d5a02b307d05132ef204d60dae8eff59535d03cbb63c932", - "0420a1b63c6e56e27412daf040304d371032d866707aa0be103b8ed5b83ce7c785000e908fdbe9ae673d97202d8b6659c82fd11ffa89b403309b388282a62b8aad", - "0xde7c3bffe1205adc8c2dd654ecf8dece33efdb54", - "-99We6jDdOZwfYj_1N1a5VCX-X1brrcKRKZbG5LQDhYTU_2ObTuBRBU5gk0zG7hb5yizZiYUR0CS1y3Zt0H-yQ", - SIG(27, "QWv2w5Mma5RncmBJst1UsBtA8IwWJV4UI9V9AqETcqI=", "PZrS9WhDochBeH6DqlCgnqb2tHmIjIZjm8+Av0Lxr/0=")) - - ) - -} - diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/SignerTests.kt b/signer/src/androidTest/java/com/uport/sdk/signer/SignerTests.kt deleted file mode 100644 index 143df719..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/SignerTests.kt +++ /dev/null @@ -1,336 +0,0 @@ -package com.uport.sdk.signer - -import android.content.Context -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import com.uport.sdk.signer.encryption.KeyProtection -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.junit.Assert.* -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.kethereum.crypto.model.PrivateKey -import org.kethereum.crypto.signMessage -import org.kethereum.crypto.toECKeyPair -import org.kethereum.extensions.hexToBigInteger -import org.spongycastle.util.encoders.Hex -import org.walleth.khex.hexToByteArray -import org.walleth.khex.toNoPrefixHexString -import java.math.BigInteger -import java.util.* -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -@RunWith(AndroidJUnit4::class) -class SignerTests { - - private lateinit var context: Context - - @Before - fun runBeforeEachTest() { - context = InstrumentationRegistry.getTargetContext() - } - - @Test - fun testKeyCreationAndUsage() { - val latch = CountDownLatch(1) - - val signer = UportSigner() - signer.createKey(context, KeyProtection.Level.SIMPLE) { err, address, pubKey -> - - assertNull(err) - - assertTrue(address.matches("^0x[0-9a-fA-F]+$".toRegex())) - - val pubKeyBytes = pubKey.decodeBase64() - assertEquals(65, pubKeyBytes.size) - - UportSigner().signJwtBundle(context, address, "hello".toBase64().padBase64(), "") { _, _ -> - latch.countDown() - } - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testKeyImportAndUsage() { - val privKeyBytes = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38".hexToByteArray() - val latch = CountDownLatch(1) - - val signer = UportSigner() - signer.saveKey(context, KeyProtection.Level.SIMPLE, privKeyBytes) { err, address, pubKey -> - - assertNull(err) - - assertTrue(address.matches("^0x[0-9a-fA-F]+$".toRegex())) - - val pubKeyBytes = pubKey.decodeBase64() - assertEquals(65, pubKeyBytes.size) - - UportSigner().signJwtBundle(context, address, "hello".toBase64().padBase64(), "") { _, _ -> - latch.countDown() - } - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testKeyImportAndUsageMulti() { - val privKeyBytes = "278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f".hexToByteArray() - - val refData1 = "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3NpZlEuZXlKcGMzTWlPaUl6TkhkcWMzaDNkbVIxWVc1dk4wNUdRemgxYWs1S2JrWnFZbUZqWjFsbFYwRTRiU0lzSW1saGRDSTZNVFE0TlRNeU1URXpNeXdpWTJ4aGFXMXpJanA3SW01aGJXVWlPaUpDYjJJaWZTd2laWGh3SWpveE5EZzFOREEzTlRNemZR" - val refSignature1 = "sg1oJ7J_f2pWaX2JwqzA61oWMUK5v0LYVxUp3PvG7Y25CVYWPyQ6UhA7U9d4w3Ny74k7ryMaUz7En5RSL4pyXg".decodeJose(28) - - val refData2 = "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3NpZlEuZXlKcGMzTWlPaUl6TkhkcWMzaDNkbVIxWVc1dk4wNUdRemgxYWs1S2JrWnFZbUZqWjFsbFYwRTRiU0lzSW1saGRDSTZNVFE0TlRNeU1URXpNekF3TUN3aVkyeGhhVzF6SWpwN0ltNWhiV1VpT2lKQ2IySWlmU3dpWlhod0lqb3hORGcxTkRBM05UTXpNREF3ZlE=" - val refSignature2 = "XJlwY1KrGRa53oHjz6vjsJadn-Er1ZW6WvLg1KiBQonV9vwqan-hAvn4tNFh7qyZMxxa3xyO7wN7GNuz6_UJ5Q".decodeJose(27) - - val refData3 = "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKRlV6STFOa3NpZlEuZXlKcGMzTWlPaUl6TkhkcWMzaDNkbVIxWVc1dk4wNUdRemgxYWs1S2JrWnFZbUZqWjFsbFYwRTRiU0lzSW1saGRDSTZNVFE0TlRNeU1URXpNeXdpWTJ4aGFXMXpJanA3SW01aGJXVWlPaUpDYjJJaWZTd2laWGh3SWpveU5EZzFNekl4TVRNemZR" - val refSignature3 = "yHkI8fY42iquI-3CSM0k75cJQ4X1DoiGV436YgFQIhJUvjO17q01KhJv2jXviCQrstYe7MZpmJE4SxTvCoC1qQ".decodeJose(27) - - val latch = CountDownLatch(3) - - val signer = UportSigner() - signer.saveKey(context, KeyProtection.Level.SIMPLE, privKeyBytes) { err, address, _ -> - - assertNull(err) - - assertEquals("0xf3beac30c498d9e26865f34fcaa57dbb935b0d74", address) - - UportSigner().signJwtBundle(context, address, refData1, "") { signerErr, sig -> - assertNull(signerErr) - assertEquals(refSignature1, sig) - latch.countDown() - } - - UportSigner().signJwtBundle(context, address, refData2, "") { signerErr, sig -> - assertNull(signerErr) - assertEquals(refSignature2, sig) - latch.countDown() - } - - UportSigner().signJwtBundle(context, address, refData3, "") { signerErr, sig -> - assertNull(signerErr) - assertEquals(refSignature3, sig) - latch.countDown() - } - - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testPublicKey1() { - val referencePrivateKey = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38" - val referencePublicKey = "04bf42759e6d2a684ef64a8210c55bf2308e4101f78959ffa335ff045ef1e4252b1c09710281f8971b39efed7bfb61ae381ed73b9faa5a96f17e00c1a4c32796b1" - val keyPair = PrivateKey(referencePrivateKey.hexToBigInteger()).toECKeyPair() - val pubKeyBytes = keyPair.getUncompressedPublicKeyWithPrefix() - val pubKeyHex = pubKeyBytes.toNoPrefixHexString() - - assertEquals(referencePublicKey, pubKeyHex) - } - - - @Test - fun keyImportGeneratesProperPublicKeyAndAddress() { - val privKeyBytes = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38".hexToByteArray() - - val referencePublicKey = "BL9CdZ5tKmhO9kqCEMVb8jCOQQH3iVn/ozX/BF7x5CUrHAlxAoH4lxs57+17+2GuOB7XO5+qWpbxfgDBpMMnlrE=" - val referenceAddress = "0x45c4EBd7Ffb86891BA6f9F68452F9F0815AAcD8b".toLowerCase() - - val latch = CountDownLatch(1) - - val signer = UportSigner() - signer.saveKey(context, KeyProtection.Level.SIMPLE, privKeyBytes) { err, address, pubKey -> - - assertNull(err) - - assertEquals(referenceAddress, address) - - assertEquals(referencePublicKey, pubKey) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testPublicKey2() { - val keypair = PrivateKey("278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f".hexToBigInteger()).toECKeyPair() - val pubKeyBytes = keypair.getUncompressedPublicKeyWithPrefix() - val pubKeyEnc = Hex.toHexString(pubKeyBytes) - assertEquals("04fdd57adec3d438ea237fe46b33ee1e016eda6b585c3e27ea66686c2ea535847946393f8145252eea68afe67e287b3ed9b31685ba6c3b00060a73b9b1242d68f7", pubKeyEnc) - } - - @Test - fun testJwtJose() { - val referencePrivateKey = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38" - val referenceSignature = "N0vw5-xCGN8XN4Q7E8XppJJi0Dch92MhMExZBqPLxJKhYYWxrb2HoY1FQ1YGC011DG1YzzdsbV1_0nIQ0ONKOg" - - val msg = "Hello, world!".toByteArray() - - val keyPair = PrivateKey(referencePrivateKey.hexToBigInteger()).toECKeyPair() - - val sigData = UportSigner().signJwt(msg, keyPair).getJoseEncoded() - - assertEquals(referenceSignature, sigData) - } - - @Test - fun testJwtDer() { - val referencePrivateKey = "5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38" - val referenceSignature = "30450220374bf0e7ec4218df1737843b13c5e9a49262d03721f76321304c5906a3cbc492022100a16185b1adbd87a18d454356060b4d750c6d58cf376c6d5d7fd27210d0e34a3a" - - val msg = "Hello, world!".toByteArray() - - val keyPair = PrivateKey(referencePrivateKey.hexToBigInteger()).toECKeyPair() - - val sigData = UportSigner().signJwt(msg, keyPair).getDerEncoded() - - assertEquals(referenceSignature, sigData) - } - - @Test - fun testJwtComponents() { - val referencePrivateKey = Hex.decode("5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38") - - val referenceR = "374bf0e7ec4218df1737843b13c5e9a49262d03721f76321304c5906a3cbc492".hexToBigInteger() - val referenceS = "a16185b1adbd87a18d454356060b4d750c6d58cf376c6d5d7fd27210d0e34a3a".hexToBigInteger() - - val msg = "Hello, world!".toByteArray() - - val keyPair = PrivateKey(referencePrivateKey).toECKeyPair() - - val sigData = UportSigner().signJwt(msg, keyPair) - - assertEquals(referenceR, sigData.r) - assertEquals(referenceS, sigData.s) - } - - @Test - fun testSignTxComponents() { - val referencePrivKeyBytes = "NobiRYkMf5l3Zrc6Idjln2OF4SCIMa84YldHkMvD0Vg=".decodeBase64() - - val referenceR = BigInteger(1, "gJ47XvJfSjsDkTni+3D3C2NuuonHejsB4MccGjbYQSY=".decodeBase64()) - val referenceS = BigInteger(1, "OFJN/NPkEstrw39FlLutEEtnZLsUxk5CxplzAQbRiFo=".decodeBase64()) - - val rawTransaction = "84CFC6Q7dACDL+/YlJ4gaMziLeTh6A8Vy3HvQ1ogo7N8iA3gtrOnZAAAiQq83vASNFZ4kA==".decodeBase64() - - val keyPair = PrivateKey(referencePrivKeyBytes).toECKeyPair() - - val sigData = keyPair.signMessage(rawTransaction) - - val obtainedR = sigData.r - val obtainedS = sigData.s - - assertEquals(referenceR, obtainedR) - assertEquals(referenceS, obtainedS) - } - - @Test - fun testEncStorage() { - val signer = UportSigner() - var latch = CountDownLatch(1) - - val label = "whatever" - val payload = "foobar" - - signer.storeEncryptedPayload(context, - KeyProtection.Level.SIMPLE, - label, - payload.toByteArray() - ) { err, result -> - assertNull(err) - assertTrue(result) - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - - latch = CountDownLatch(1) - signer.loadEncryptedPayload(context, - label, - "just decrypt it already" - ) { err, resultBytes -> - assertNull(err) - assertEquals(String(resultBytes), payload) - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun testAllAddresses() { - val signer = UportSigner() - - val rand = Random() - val privKeys = LinkedList() - val addresses = LinkedList() - - val iter = 10 - val createLatch = CountDownLatch(iter) - - //create and store a bunch of addresses - for (i in 0..iter) { - val pk = ByteArray(32) - rand.nextBytes(pk) - privKeys.push(pk) - - signer.saveKey(context, - KeyProtection.Level.SIMPLE, - pk - ) { err, address, _ -> - assertNull(err) - addresses.push(address) - createLatch.countDown() - } - } - - createLatch.await(20, TimeUnit.SECONDS) - - //check if the addresses are read back successfully from storage - val readLatch = CountDownLatch(1) - val storedAddressList = LinkedList() - signer.allAddresses(context - ) { list -> - storedAddressList.addAll(list) - readLatch.countDown() - } - readLatch.await(20, TimeUnit.SECONDS) - - assertTrue(storedAddressList.containsAll(addresses)) - - } - - @Test - fun testDeleteKey() { - val referencePrivateKey = Hex.decode("5047c789919e943c559d8c134091d47b4642122ba0111dfa842ef6edefb48f38") - - val tested = UportSigner() - - var keyHandle = "" - - var latch = CountDownLatch(1) - tested.saveKey(context, KeyProtection.Level.SIMPLE, referencePrivateKey) { err, addr, _ -> - assertNull(err) - keyHandle = addr - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - - tested.deleteKey(context, keyHandle) - - latch = CountDownLatch(1) - tested.allAddresses(context) { all -> - assertFalse(all.contains(keyHandle)) - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } -} - diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/UserInteractionContextTests.kt b/signer/src/androidTest/java/com/uport/sdk/signer/UserInteractionContextTests.kt deleted file mode 100644 index a34b3cc6..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/UserInteractionContextTests.kt +++ /dev/null @@ -1,117 +0,0 @@ -package com.uport.sdk.signer - -import android.support.test.InstrumentationRegistry -import com.uport.sdk.signer.UportSigner.Companion.ERR_ACTIVITY_DOES_NOT_EXIST -import com.uport.sdk.signer.encryption.KeyProtection -import com.uport.sdk.signer.testutil.ensureKeyIsImportedInTargetContext -import com.uport.sdk.signer.testutil.ensureSeedIsImportedInTargetContext -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Test -import org.kethereum.bip39.generateMnemonic -import org.kethereum.bip39.wordlists.WORDLIST_ENGLISH -import java.security.SecureRandom -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class UserInteractionContextTests { - - private val phrase = generateMnemonic(wordList = WORDLIST_ENGLISH) - private val key = ByteArray(32).apply { SecureRandom().nextBytes(this) } - - private val context = InstrumentationRegistry.getTargetContext() - //import a key that needs user authentication - private val seedHandle = ensureSeedIsImportedInTargetContext(phrase, KeyProtection.Level.PROMPT) - private val keyHandle = ensureKeyIsImportedInTargetContext(key, KeyProtection.Level.PROMPT) - - @Test - fun shouldThrowOnShowSeedWhenUsingActivityDependentKey() { - - val latch = CountDownLatch(1) - UportHDSigner().showHDSeed(context, seedHandle, "this is shown to the user") { err, _ -> - - assertNotNull(err!!) - assertTrue(err.message?.contains(ERR_ACTIVITY_DOES_NOT_EXIST) ?: false) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun shouldThrowOnSignJwtWhenUsingActivityDependentKey() { - - val somePayloadData = "payload to be signed".toByteArray() - val payload = somePayloadData.toBase64().padBase64() - - val latch = CountDownLatch(1) - UportHDSigner().signJwtBundle(context, seedHandle, UportHDSigner.UPORT_ROOT_DERIVATION_PATH, payload, "this is shown to the user") { err, _ -> - - assertNotNull(err!!) - assertTrue(err.message?.contains(ERR_ACTIVITY_DOES_NOT_EXIST) ?: false) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun shouldThrowOnSignTxWhenUsingActivityDependentKey() { - - val somePayloadData = "payload to be signed".toByteArray() - val payload = somePayloadData.toBase64().padBase64() - - val latch = CountDownLatch(1) - UportHDSigner().signTransaction(context, seedHandle, UportHDSigner.UPORT_ROOT_DERIVATION_PATH, payload, "this is shown to the user") { err, _ -> - - assertNotNull(err!!) - assertTrue(err.message?.contains(ERR_ACTIVITY_DOES_NOT_EXIST) ?: false) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - - @Test - fun shouldThrowOnSignJwtSimpleWhenUsingActivityDependentKey() { - - val somePayloadData = "payload to be signed".toByteArray() - val payload = somePayloadData.toBase64().padBase64() - - val latch = CountDownLatch(1) - UportSigner().signJwtBundle(context, keyHandle, payload, "this is shown to the user") { err, _ -> - - assertNotNull(err!!) - assertTrue(err.message?.contains(ERR_ACTIVITY_DOES_NOT_EXIST) ?: false) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - - @Test - fun shouldThrowOnSignTxSimpleWhenUsingActivityDependentKey() { - - val somePayloadData = "payload to be signed".toByteArray() - val payload = somePayloadData.toBase64().padBase64() - - val latch = CountDownLatch(1) - UportSigner().signTransaction(context, keyHandle, payload, "this is shown to the user") { err, _ -> - - assertNotNull(err!!) - assertTrue(err.message?.contains(ERR_ACTIVITY_DOES_NOT_EXIST) ?: false) - - latch.countDown() - } - - latch.await(20, TimeUnit.SECONDS) - } - -} \ No newline at end of file diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtectionTest.kt b/signer/src/androidTest/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtectionTest.kt deleted file mode 100644 index c01a3735..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtectionTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.uport.sdk.signer.encryption - -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import org.junit.Assert.assertArrayEquals -import org.junit.Assert.assertNull -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.util.* -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -@RunWith(AndroidJUnit4::class) -class SimpleAsymmetricProtectionTest { - - @Before - fun setUp() { - - } - - @Test - fun encryptDecryptRandomBlobsOfMultipleSizes() { - val context = InstrumentationRegistry.getTargetContext() - SimpleAsymmetricProtection().genKey(context) - - val textSize = listOf(128)//, 256, 512, 1024, 2048, 4096, 13, 1234, 6123) - - textSize.forEach { - val latch = CountDownLatch(1) - val blob = ByteArray(it) - Random().nextBytes(blob) - SimpleAsymmetricProtection().encrypt(context, "", blob) { eerr, ciphertext -> - - assertNull("failed to encrypt a blob of $it bytes", eerr) - - SimpleAsymmetricProtection().decrypt(context, "", ciphertext) { derr, decrypted -> - - assertNull("failed to decrypt a blob of $it bytes", derr) - - assertArrayEquals(blob, decrypted) - - latch.countDown() - } - } - - latch.await(20, TimeUnit.SECONDS) - } - } -} \ No newline at end of file diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/storage/ProtectedSharedPreferencesTest.kt b/signer/src/androidTest/java/com/uport/sdk/signer/storage/ProtectedSharedPreferencesTest.kt deleted file mode 100644 index 1b981051..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/storage/ProtectedSharedPreferencesTest.kt +++ /dev/null @@ -1,346 +0,0 @@ -package com.uport.sdk.signer.storage - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 -import org.junit.Assert.* -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class ProtectedSharedPreferencesTest { - - private lateinit var context: Context - private lateinit var prefs: ProtectedSharedPreferences - - @Before - fun before() { - context = InstrumentationRegistry.getTargetContext() - val basePrefs = context.getSharedPreferences("test_prefs", MODE_PRIVATE) - prefs = ProtectedSharedPreferences(context, basePrefs) - } - - @Test - fun contains() { - - val key = "some key" - val value = "some value" - - prefs.edit().putString(key, value).apply() - - assertTrue(prefs.contains(key)) - } - - @Test - fun getString() { - - val key = "some string key" - val value = "some value" - - prefs.edit().putString(key, value).apply() - - assertEquals(value, prefs.getString(key, "not what I want")) - } - - @Test - fun canStoreEmptyString() { - - val key = "some empty-string key" - val value = "" - - prefs.edit().putString(key, value).apply() - - assertEquals(value, prefs.getString(key, "not what I want")) - } - - @Test - fun canStoreEmptyStringSet() { - - val key = "some empty-string-set key" - val value = setOf(/*nothing*/) - - prefs.edit().putStringSet(key, value).apply() - - assertEquals(value, prefs.getStringSet(key, null)) - } - - @Test - fun canStoreStringSetWithEmptyString() { - - val key = "some string-set key for blanks" - val value = setOf("") - - prefs.edit().putStringSet(key, value).apply() - - assertEquals(value, prefs.getStringSet(key, null)) - } - - @Test - fun getInt() { - - val key = "some int key" - val value = 42 - - prefs.edit().putInt(key, value).apply() - - assertEquals(value, prefs.getInt(key, value + 1)) - } - - @Test - fun getLong() { - - val key = "some long key" - val value = 42L - - prefs.edit().putLong(key, value).apply() - - assertEquals(value, prefs.getLong(key, value + 1)) - } - - @Test - fun getFloat() { - - val key = "some float key" - val value = 42.0f - - prefs.edit().putFloat(key, value).apply() - - assertEquals(value, prefs.getFloat(key, value + 3.14f)) - } - - @Test - fun getStringSet() { - - val key = "some string set key" - val value = setOf("one", "two", "three") - - prefs.edit().putStringSet(key, value).apply() - - assertEquals(value, prefs.getStringSet(key, null)) - } - - @Test - fun getBoolean() { - val key = "some bool key" - - prefs.edit().putBoolean(key, true).apply() - - assertTrue(prefs.getBoolean(key, false)) - } - - @Test - fun clear() { - prefs.edit().clear().apply() - - assertTrue(prefs.all.isEmpty()) - - } - - @Test - fun all() { - - prefs.edit().clear().apply() - - prefs.edit() - .putBoolean("b", true) - .putString("s", "hello") - .putFloat("f", 3.14f) - .putLong("l", 42L) - .putInt("i", 43) - .putStringSet("set", setOf("hello", "world", "!")) - .apply() - - assertTrue(prefs.all.containsKey("b")) - assertTrue(prefs.all.containsKey("s")) - assertTrue(prefs.all.containsKey("f")) - assertTrue(prefs.all.containsKey("l")) - assertTrue(prefs.all.containsKey("i")) - assertTrue(prefs.all.containsKey("set")) - - assertTrue(prefs.all.containsValue(true)) - assertTrue(prefs.all.containsValue("hello")) - assertTrue(prefs.all.containsValue(3.14f)) - assertTrue(prefs.all.containsValue(42L)) - assertTrue(prefs.all.containsValue(43)) - assertTrue(prefs.all.containsValue(setOf("hello", "world", "!"))) - - } - - @Test - fun remove() { - prefs.edit() - .putString("key", "value") - .apply() - - prefs.edit().remove("key").apply() - - assertFalse(prefs.contains("key")) - - } - - @Test - fun commitSameAsApply() { - prefs.edit() - .clear() - .putString("key", "value") - .putInt("key_i", 12) - .putBoolean("key_b", true) - .apply() - - val asApplied = prefs.all - - prefs.edit() - .clear() - .putString("key", "value") - .putInt("key_i", 12) - .putBoolean("key_b", true) - .commit() - - val asCommitted = prefs.all - - assertEquals(asApplied, asCommitted) - - } - - @Test - fun encryptionVaries() { - val basePrefs = prefs.delegate - - val value = "some string" - - prefs.edit() - .putString("first", value) - .putString("second", value) - .apply() - - val readFirst = basePrefs.getString("s:first", "same") - val readSecond = basePrefs.getString("s:second", "same") - - assertNotEquals(readFirst, readSecond) - } - - @Test - fun clearsUnencryptedData() { - val originalPrefs = context.getSharedPreferences("dummy", MODE_PRIVATE) - originalPrefs.edit() - .putBoolean("b_bla", true) - .putString("s_bla", "hello") - .putFloat("f_bla", 3.14f) - .putLong("l_bla", 42L) - .putInt("i_bla", 43) - .putStringSet("set_bla", setOf("hello", "world", "!")) - .apply() - - val wrappedPrefs = ProtectedSharedPreferences(context, originalPrefs) - - setOf("b", "s", "f", "l", "i", "set").forEach { - assertFalse(originalPrefs.contains("${it}_bla")) - assertTrue("was looking for key ${it}_bla but did not find it", wrappedPrefs.contains("${it}_bla")) - } - } - - - @Test - fun clearsUnreadableDataOnContains() { - val originalPrefs = context.getSharedPreferences("unreadable", MODE_PRIVATE) - - val wrappedPrefs = ProtectedSharedPreferences(context, originalPrefs) - - //force some prefix collisions to make decryption fail - originalPrefs.edit() - .putBoolean("b:b_bla", true) - .putString("s:s_bla", "hello") - .putFloat("f:f_bla", 3.14f) - .putLong("l:l_bla", 42L) - .putInt("i:i_bla", 43) - .putStringSet("e:set_bla", setOf("hello", "world", "!")) - .apply() - - setOf("b", "s", "f", "l", "i", "set").forEach { - - assertFalse(wrappedPrefs.contains("${it}_bla")) - - } - - //the unreadable prefs should have been cleared by the above calls - assertTrue(originalPrefs.all.isEmpty()) - assertTrue(wrappedPrefs.all.isEmpty()) - } - - @Test - fun returnsDefaultsWhenDecryptionFails() { - val originalPrefs = InstrumentationRegistry.getContext().getSharedPreferences("defaultable", MODE_PRIVATE) - - val wrappedPrefs = ProtectedSharedPreferences(context, originalPrefs) - - //force some prefix collisions to make decryption fail - originalPrefs.edit() - .putBoolean("b:b_bla", true) - .putString("s:s_bla", "hello") - .putFloat("f:f_bla", 3.14f) - .putLong("l:l_bla", 42L) - .putInt("i:i_bla", 43) - .putStringSet("e:set_bla", setOf("hello", "world", "!")) - .apply() - - assertEquals(false, wrappedPrefs.getBoolean("b_bla", false)) - assertEquals("goodbye", wrappedPrefs.getString("s_bla", "goodbye")) - assertEquals(6.28f, wrappedPrefs.getFloat("f_bla", 6.28f)) - assertEquals(-942L, wrappedPrefs.getLong("l_bla", -942L)) - assertEquals(-943, wrappedPrefs.getInt("i_bla", -943)) - assertEquals(setOf("goodbye", "world"), wrappedPrefs.getStringSet("set_bla", setOf("goodbye", "world").toMutableSet())) - - //the unreadable prefs should have been cleared by the above calls - assertTrue(originalPrefs.all.isEmpty()) - assertTrue(wrappedPrefs.all.isEmpty()) - } - - @Test - fun canOverwriteData() { - - val key = "myKey" - val value = setOf("hello", "world") - prefs.edit().putStringSet(key, value).apply() - assertEquals(value, prefs.getStringSet(key, null)) - - val newValue = setOf("goodbye", "worlds") - prefs.edit().putStringSet(key, newValue).apply() - assertEquals(newValue, prefs.getStringSet(key, null)) - } - - @Test - fun canOverwriteDataAndType() { - - val key = "myKey" - val value = setOf("hello", "world") - prefs.edit().putStringSet(key, value).apply() - assertEquals(value, prefs.getStringSet(key, null)) - - val newValue = 42.0f - prefs.edit().putFloat(key, newValue).apply() - assertEquals(newValue, prefs.getFloat(key, 3.14f)) - } - - @Test - fun readsDefaultsWhenDatatypeMismatch() { - - val key = "myKey" - val value = setOf("hello", "world") - prefs.edit().putStringSet(key, value).apply() - assertEquals(value, prefs.getStringSet(key, null)) - - assertEquals("whatever", prefs.getString(key, "whatever")) - } - - @Test - fun canStoreBigString() { - val key = "long piece of string" - val value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris et nisi metus. Proin enim urna, molestie nec quam id, efficitur laoreet sem. Ut hendrerit ac lectus at euismod. Donec cursus, metus quis gravida accumsan, orci ipsum efficitur ex, vitae ullamcorper turpis nibh id velit. Morbi nec tincidunt massa. Pellentesque accumsan sapien tristique felis molestie euismod. Ut sit amet rutrum mauris, eu tristique risus. Ut vitae quam id lectus scelerisque auctor. Sed arcu magna, egestas ut orci eget, imperdiet fermentum orci. Donec posuere mauris ante, et suscipit dolor posuere sit amet. Sed viverra laoreet pellentesque. Mauris neque risus, aliquam ut ultrices sed, laoreet a erat. Integer fringilla felis nec metus interdum, ac pellentesque dolor consequat. Nulla eros elit, commodo eget dolor sed, bibendum blandit elit. Duis arcu dolor, dignissim et diam ac, tempus ullamcorper mi. Nulla non lacus neque. Duis eget ex magna. Curabitur viverra volutpat massa eget vulputate. Nam elementum urna eu ante luctus, et aliquet tellus imperdiet. Cras pulvinar metus eget eros pretium, nec ullamcorper ipsum vestibulum. Praesent porttitor, dolor ac feugiat ultricies, dui libero tincidunt ex, in semper tellus massa pretium quam. Nulla sollicitudin pharetra massa, at scelerisque libero luctus sed. Proin sit amet lacus vel nunc molestie sollicitudin. Aliquam dolor lorem, rutrum vel cursus sit amet, vestibulum et lorem. Morbi lacinia erat id diam venenatis rutrum. Quisque interdum lectus id augue vestibulum congue. Cras libero ipsum, congue consectetur tellus sit amet, tincidunt pulvinar ligula. Duis finibus mauris ac orci ultrices lacinia. Sed interdum sodales commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus eu nibh neque. Cras viverra malesuada odio a volutpat. Fusce tincidunt felis id dolor volutpat sodales. Praesent purus lectus, maximus in finibus facilisis, finibus eu dui. Donec porta, felis id condimentum ullamcorper, mauris nisi consectetur leo, quis consectetur est velit id mi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque volutpat purus lectus, id volutpat mauris auctor in. Nam ultricies lectus rutrum leo blandit, nec condimentum felis efficitur. Phasellus non tincidunt tellus. Suspendisse potenti. Etiam ac est risus. Nullam eget augue diam. Pellentesque sed molestie ligula. Mauris justo elit, elementum eget massa efficitur, vehicula sodales ante. Fusce eu lobortis mi. Nunc sed lectus nec dolor ultrices vehicula. Sed ut nisl molestie, ultrices ligula eget, consectetur sem. Maecenas erat elit, facilisis ac luctus ac, congue in libero. Nulla in congue odio. Proin pretium mattis erat a ultricies. Mauris velit justo, fringilla non sapien vel, blandit eleifend sapien. Donec eu dignissim erat. Nam vel efficitur turpis, non congue justo. Maecenas id lectus sapien. Vivamus aliquet ultrices molestie. Sed volutpat dolor quis nunc euismod gravida. Phasellus ut suscipit nibh, at scelerisque tellus. Donec tincidunt lectus eleifend lectus maximus, vitae rutrum sapien hendrerit. Nunc bibendum et augue in gravida. Duis viverra, nisi vel imperdiet dapibus, nulla massa mollis libero, a viverra magna augue nec dolor. Integer vehicula augue vitae nisl eleifend venenatis. Nunc vestibulum leo at hendrerit iaculis. Donec vulputate maximus neque. Fusce accumsan varius semper. Quisque ante enim, interdum in odio id, posuere rutrum mi. Quisque ultricies mollis viverra. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla finibus est mi, at rutrum ipsum posuere eu. Ut feugiat elementum pharetra. Nullam mollis ipsum quis lectus sodales aliquam. Duis odio massa, tempus eget tristique sed, vestibulum eget nunc. Sed volutpat venenatis suscipit. Sed placerat, risus cursus pharetra varius, sapien sapien pretium dui, in auctor lacus magna commodo libero. Donec feugiat, nibh sed egestas viverra, nibh justo suscipit tellus, id ornare velit lectus a nunc. Etiam ut magna in dolor molestie molestie in dapibus nulla. Mauris egestas ligula nec quam rhoncus efficitur eu sed." - - prefs.edit().putString(key, value).apply() - - assertEquals(value, prefs.getString(key, "not what I want")) - } -} \ No newline at end of file diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestDummyActivity.kt b/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestDummyActivity.kt deleted file mode 100644 index fae54cbb..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestDummyActivity.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.uport.sdk.signer.testutil - -import android.support.v7.app.AppCompatActivity - -class TestDummyActivity : AppCompatActivity() { - -} \ No newline at end of file diff --git a/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestHelpers.kt b/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestHelpers.kt deleted file mode 100644 index 4c8a1b76..00000000 --- a/signer/src/androidTest/java/com/uport/sdk/signer/testutil/TestHelpers.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.uport.sdk.signer.testutil - -import android.support.test.InstrumentationRegistry -import com.uport.sdk.signer.UportHDSigner -import com.uport.sdk.signer.UportSigner -import com.uport.sdk.signer.encryption.KeyProtection -import org.junit.Assert -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -/** - * synchronously imports a given seed phrase at the desired protection level - */ -fun ensureSeedIsImportedInTargetContext(phrase: String, level: KeyProtection.Level = KeyProtection.Level.SIMPLE): String { - val targetContext = InstrumentationRegistry.getTargetContext() - val latch = CountDownLatch(1) - lateinit var handle: String - UportHDSigner().importHDSeed(targetContext, level, phrase) { err, rootAddress, _ -> - Assert.assertNull(err) - handle = rootAddress - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - return handle -} - -/** - * synchronously imports a given private key at the desired protection level - */ -fun ensureKeyIsImportedInTargetContext(key: ByteArray, level: KeyProtection.Level = KeyProtection.Level.SIMPLE): String { - val targetContext = InstrumentationRegistry.getTargetContext() - val latch = CountDownLatch(1) - lateinit var handle: String - UportSigner().saveKey(targetContext, level, key) { err, rootAddress, _ -> - Assert.assertNull(err) - handle = rootAddress - latch.countDown() - } - latch.await(20, TimeUnit.SECONDS) - return handle -} \ No newline at end of file diff --git a/signer/src/androidTest/res/values/styles.xml b/signer/src/androidTest/res/values/styles.xml deleted file mode 100644 index ca668843..00000000 --- a/signer/src/androidTest/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/signer/src/main/AndroidManifest.xml b/signer/src/main/AndroidManifest.xml deleted file mode 100644 index b60c00b0..00000000 --- a/signer/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/signer/src/main/java/com/uport/sdk/signer/Extensions.kt b/signer/src/main/java/com/uport/sdk/signer/Extensions.kt deleted file mode 100644 index a5449d84..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/Extensions.kt +++ /dev/null @@ -1,133 +0,0 @@ -@file:Suppress("TooManyFunctions") - -package com.uport.sdk.signer - -import android.os.Build -import com.uport.sdk.signer.UportSigner.Companion.COMPRESSED_PUBLIC_KEY_SIZE -import com.uport.sdk.signer.UportSigner.Companion.UNCOMPRESSED_PUBLIC_KEY_SIZE -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import me.uport.sdk.core.toBase64UrlSafe -import org.kethereum.crypto.decompressKey -import org.kethereum.crypto.model.ECKeyPair -import org.kethereum.crypto.model.PRIVATE_KEY_SIZE -import org.kethereum.crypto.model.PublicKey -import org.kethereum.extensions.toBigInteger -import org.kethereum.extensions.toBytesPadded -import org.kethereum.model.SignatureData -import org.spongycastle.asn1.ASN1EncodableVector -import org.spongycastle.asn1.ASN1Encoding -import org.spongycastle.asn1.ASN1Integer -import org.spongycastle.asn1.DERSequence -import org.walleth.khex.toNoPrefixHexString -import java.io.ByteArrayOutputStream -import java.math.BigInteger -import java.util.* - -const val SIG_COMPONENT_SIZE = PRIVATE_KEY_SIZE -const val SIG_SIZE = SIG_COMPONENT_SIZE * 2 -const val SIG_RECOVERABLE_SIZE = SIG_SIZE + 1 - -/** - * Returns the JOSE encoding of the standard signature components (joined by empty string) - * - * @param recoverable If this is true then the buffer returned gets an extra byte with the - * recovery param shifted back to [0, 1] ( as opposed to [27,28] ) - */ -fun SignatureData.getJoseEncoded(recoverable: Boolean = false): String { - val size = if (recoverable) - SIG_RECOVERABLE_SIZE - else - SIG_SIZE - - val bos = ByteArrayOutputStream(size) - bos.write(this.r.toBytesPadded(SIG_COMPONENT_SIZE)) - bos.write(this.s.toBytesPadded(SIG_COMPONENT_SIZE)) - if (recoverable) { - bos.write(byteArrayOf((this.v - 27).toByte())) - } - return bos.toByteArray().toBase64UrlSafe() -} - -fun String.decodeJose(recoveryParam: Byte = 27): SignatureData = this.decodeBase64().decodeJose(recoveryParam) - -fun ByteArray.decodeJose(recoveryParam: Byte = 27): SignatureData { - val rBytes = Arrays.copyOfRange(this, 0, SIG_COMPONENT_SIZE) - val sBytes = Arrays.copyOfRange(this, SIG_COMPONENT_SIZE, SIG_SIZE) - val v = if (this.size > SIG_SIZE) - this[SIG_SIZE].let { - if (it < 27) (it + 27).toByte() else it - } - else - recoveryParam - return SignatureData(BigInteger(1, rBytes), BigInteger(1, sBytes), v) -} - -/** - * Returns the DER encoding of the standard signature components - */ -fun SignatureData.getDerEncoded(): String { - - val v = ASN1EncodableVector() - v.add(ASN1Integer(this.r)) - v.add(ASN1Integer(this.s)) - return DERSequence(v) - .getEncoded(ASN1Encoding.DER) - .toNoPrefixHexString() -} - -private const val DELIMITER = "]" - -fun packCiphertext(vararg data: ByteArray): String = - data.joinToString(DELIMITER) { it.toBase64().padBase64() } - -fun unpackCiphertext(ciphertext: String): List = - ciphertext - .split(DELIMITER) - .map { it.decodeBase64() } - -/** - * Decompresses the public key of this pair and returns the uncompressed version, including prefix - */ -fun ECKeyPair.getUncompressedPublicKeyWithPrefix(): ByteArray { - val pubBytes = this.publicKey.normalize().key.toBytesPadded(UportSigner.UNCOMPRESSED_PUBLIC_KEY_SIZE) - pubBytes[0] = 0x04 - return pubBytes -} - -/** - * Returns the uncompressed version of this publicKey, including prefix - */ -fun PublicKey.getUncompressedPublicKeyWithPrefix(): ByteArray { - val pubBytes = this.normalize().key.toBytesPadded(UportSigner.UNCOMPRESSED_PUBLIC_KEY_SIZE) - pubBytes[0] = 0x04 - return pubBytes -} - -/** - * Transforms a PublicKey into its normalized version which is decompressed and has no prefix - */ -fun PublicKey.normalize(): PublicKey { - val pubBytes = this.key.toByteArray() - val normalizedBytes = when (pubBytes.size) { - UNCOMPRESSED_PUBLIC_KEY_SIZE -> pubBytes.copyOfRange(1, pubBytes.size) - COMPRESSED_PUBLIC_KEY_SIZE -> decompressKey(pubBytes) - else -> pubBytes - } - return PublicKey(normalizedBytes.toBigInteger()) -} - -/** - * represents a BigInteger as a base64 encoding of a fixed size bytearray. The [keySize] defaults to 32 bytes (the size of a private key) - */ -fun BigInteger.keyToBase64(keySize: Int = PRIVATE_KEY_SIZE): String = - this.toBytesPadded(keySize).toBase64().padBase64() - -/** - * shorthand for checking if this code is running on android M or later - */ -fun hasMarshmallow(): Boolean = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - -typealias EncryptionCallback = (err: Exception?, ciphertext: String) -> Unit -typealias DecryptionCallback = (err: Exception?, cleartext: ByteArray) -> Unit \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/KPSigner.kt b/signer/src/main/java/com/uport/sdk/signer/KPSigner.kt deleted file mode 100644 index 2b31f336..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/KPSigner.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.uport.sdk.signer - -import org.kethereum.crypto.model.PrivateKey -import org.kethereum.crypto.signMessage -import org.kethereum.crypto.signMessageHash -import org.kethereum.crypto.toAddress -import org.kethereum.crypto.toECKeyPair -import org.kethereum.extensions.hexToBigInteger -import org.kethereum.hashes.sha256 -import org.kethereum.model.SignatureData - -/** - * Simple [Signer] implementation that holds the KeyPair in memory. - * - * There is no special handling of threads for callbacks. - */ -class KPSigner(privateKey: String) : Signer { - - private val keyPair = PrivateKey(privateKey.hexToBigInteger()).toECKeyPair() - - override fun signJWT(rawPayload: ByteArray, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - try { - val sigData = signMessageHash(rawPayload.sha256(), keyPair, false) - callback(null, sigData) - } catch (err: Exception) { - callback(err, SignatureData()) - } - } - - override fun getAddress() = keyPair.toAddress().hex - - override fun signETH(rawMessage: ByteArray, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - try { - val sigData = keyPair.signMessage(rawMessage) - callback(null, sigData) - } catch (ex: Exception) { - callback(ex, SignatureData()) - } - - } - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/Signer.kt b/signer/src/main/java/com/uport/sdk/signer/Signer.kt deleted file mode 100644 index aff49dce..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/Signer.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.uport.sdk.signer - -import org.kethereum.functions.encodeRLP -import org.kethereum.model.SignatureData -import org.kethereum.model.Transaction -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -/** - * Callback type for signature results. - */ -typealias SignatureCallback = (err: Exception?, sigData: SignatureData) -> Unit - -/** - * An interface used to sign transactions or messages for uport specific operations - */ -interface Signer { - - /** - * Signs a blob of bytes that represent a RLP encoded transaction. - */ - fun signETH(rawMessage: ByteArray, callback: SignatureCallback) - - /** - * Signs a blob of bytes that represent the encoded header and payload parts of a JWT - */ - fun signJWT(rawPayload: ByteArray, callback: SignatureCallback) - - /** - * returns the ethereum address corresponding to the key that does the signing - */ - fun getAddress(): String - - /** - * - */ - fun signRawTx( - unsignedTx: Transaction, - callback: (err: Exception?, - signedEncodedTransaction: ByteArray) -> Unit) = signETH(unsignedTx.encodeRLP()) - { err, sig -> - if (err != null) { - return@signETH callback(err, byteArrayOf()) - } - return@signETH callback(null, unsignedTx.encodeRLP(sig)) - } - - companion object { - /** - * A useless signer that calls back with empty signature and has no associated address - */ - val blank = object : Signer { - override fun signETH(rawMessage: ByteArray, callback: SignatureCallback) = callback(null, SignatureData()) - override fun signJWT(rawPayload: ByteArray, callback: SignatureCallback) = callback(null, SignatureData()) - override fun getAddress(): String = "" - } - } -} - - -//////////////////////////////////////////////////// -// signer extensions - wrap callbacks as coroutines -//////////////////////////////////////////////////// - -suspend fun Signer.signRawTx(unsignedTx: Transaction): ByteArray = suspendCoroutine { continuation -> - this.signRawTx(unsignedTx) { err, signedEncodedTransaction -> - if (err != null) { - continuation.resumeWithException(err) - } else { - continuation.resume(signedEncodedTransaction) - } - } -} - -suspend fun Signer.signETH(rawMessage: ByteArray): SignatureData = suspendCoroutine { continuation -> - this.signETH(rawMessage) { err, sigData -> - if (err != null) { - continuation.resumeWithException(err) - } else { - continuation.resume(sigData) - } - } -} - -suspend fun Signer.signJWT(rawMessage: ByteArray): SignatureData = suspendCoroutine { continuation -> - this.signJWT(rawMessage) { err, sigData -> - if (err != null) { - continuation.resumeWithException(err) - } else { - continuation.resume(sigData) - } - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/UportHDSigner.kt b/signer/src/main/java/com/uport/sdk/signer/UportHDSigner.kt deleted file mode 100644 index 1abaa5fe..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/UportHDSigner.kt +++ /dev/null @@ -1,307 +0,0 @@ -package com.uport.sdk.signer - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import com.uport.sdk.signer.encryption.KeyProtection -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.kethereum.bip39.entropyToMnemonic -import org.kethereum.bip39.mnemonicToEntropy -import org.kethereum.bip39.model.MnemonicWords -import org.kethereum.bip39.toKey -import org.kethereum.bip39.validate -import org.kethereum.bip39.wordlists.WORDLIST_ENGLISH -import org.kethereum.crypto.signMessage -import org.kethereum.crypto.toAddress -import org.kethereum.model.SignatureData -import java.security.SecureRandom - -@Suppress("unused", "KDocUnresolvedReference") -class UportHDSigner : UportSigner() { - - /** - * Checks if there is ANY seed created or imported - */ - fun hasSeed(context: Context): Boolean { - - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - - val allSeeds = prefs.all.keys - .filter { label -> label.startsWith(SEED_PREFIX) } - .filter { hasCorrespondingLevelKey(prefs, it) } - - return allSeeds.isNotEmpty() - } - - /** - * Creates a 128 bit seed and stores it at the [level] encryption level. - * Calls back with the seed handle ([rootAddress]) and the Base64 encoded - * [pubKey] corresponding to it, or a non-null [err] if something broke - */ - fun createHDSeed(context: Context, level: KeyProtection.Level, callback: (err: Exception?, rootAddress: String, pubKey: String) -> Unit) { - - val entropyBuffer = ByteArray(128 / 8) - SecureRandom().nextBytes(entropyBuffer) - - val seedPhrase = entropyToMnemonic(entropyBuffer, WORDLIST_ENGLISH) - - return importHDSeed(context, level, seedPhrase, callback) - - } - - /** - * Imports a given mnemonic [phrase] - * The phrase is converted to its binary representation using bip39 rules - * and stored at the provided [level] of encryption. - * - * A rootAddress is derived from the phrase and will be used to refer to this imported phrase for future signing. - * - * Then calls back with the derived 0x `rootAddress` and base64 encoded `public Key` - * or a non-null err in case something goes wrong - */ - fun importHDSeed(context: Context, level: KeyProtection.Level, phrase: String, callback: (err: Exception?, address: String, pubKey: String) -> Unit) { - - try { -// val seedBuffer = mnemonicToSeed(phrase) - - val entropyBuffer = mnemonicToEntropy(phrase, WORDLIST_ENGLISH) - - val extendedRootKey = MnemonicWords(phrase).toKey(UPORT_ROOT_DERIVATION_PATH) - - val keyPair = extendedRootKey.keyPair - - val publicKeyBytes = keyPair.getUncompressedPublicKeyWithPrefix() - val publicKeyString = publicKeyBytes.toBase64().padBase64() - val address: String = keyPair.toAddress().hex - - val label = asSeedLabel(address) - - storeEncryptedPayload(context, - level, - label, - entropyBuffer - ) { err, _ -> - - //empty memory - entropyBuffer.fill(0) - - if (err != null) { - return@storeEncryptedPayload callback(err, "", "") - } - - return@storeEncryptedPayload callback(null, address, publicKeyString) - } - } catch (ex: Exception) { - return callback(ex, "", "") - } - } - - /** - * Deletes a seed from storage. - */ - fun deleteSeed(context: Context, label: String) { - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - prefs.edit() - //store encrypted privatekey - .remove(asSeedLabel(label)) - //mark the key as encrypted with provided security level - .remove(asLevelLabel(label)) - .apply() - } - - - /** - * Signs a transaction bundle using a key derived from a previously imported/created seed. - * - * In case the seed corresponding to the [rootAddress] requires user authentication to decrypt, - * this method will launch the decryption UI with a [prompt] and schedule a callback with the signature data - * after the decryption takes place; or a non-null error in case something goes wrong (or user cancels) - * - * The decryption UI can be a device lockscreen or fingerprint-dialog depending on the level of encryption - * requested at seed creation/import. - * - * @param context The android activity from which the signature is requested or app context if it's encrypted using [KeyProtection.Level.SIMPLE]] protection - * @param rootAddress the 0x ETH address used to refer to the previously imported/created seed - * @param txPayload the base64 encoded byte array that represents the message to be signed - * @param prompt A string that needs to be displayed to the user in case user-auth is requested - * @param callback (error, signature) called after the transaction has been signed successfully or - * with an error and empty data when it fails - */ - fun signTransaction(context: Context, rootAddress: String, derivationPath: String, txPayload: String, prompt: String, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - val (encryptionLayer, encryptedEntropy, storageError) = getEncryptionForLabel(context, asSeedLabel(rootAddress)) - - if (storageError != null) { - //storage error is also thrown if the root seed does not exist - return callback(storageError, EMPTY_SIGNATURE_DATA) - } - - encryptionLayer.decrypt(context, prompt, encryptedEntropy) { err, entropyBuff -> - - if (err != null) { - return@decrypt callback(err, EMPTY_SIGNATURE_DATA) - } - - try { - - val phrase = entropyToMnemonic(entropyBuff, WORDLIST_ENGLISH) - val extendedKey = MnemonicWords(phrase).toKey(derivationPath) - - val keyPair = extendedKey.keyPair - - val txBytes = txPayload.decodeBase64() - - val sigData = keyPair.signMessage(txBytes) - return@decrypt callback(null, sigData) - - } catch (exception: Exception) { - return@decrypt callback(exception, EMPTY_SIGNATURE_DATA) - } - - } - - } - - /** - * Signs a uPort specific JWT bundle using a key derived from a previously imported/created seed. - * - * In case the seed corresponding to the [rootAddress] requires user authentication to decrypt, - * this method will launch the decryption UI with a [prompt] and schedule a callback with the signature data - * after the decryption takes place; or a non-null error in case something goes wrong (or user cancels) - * - * The decryption UI can be a device lockscreen or fingerprint-dialog depending on the level of encryption - * requested at seed creation/import. - * - * @param context The android activity from which the signature is requested or app context if it's encrypted using [KeyProtection.Level.SIMPLE]] protection - * @param rootAddress the 0x ETH address used to refer to the previously imported/created seed - * @param data the base64 encoded byte array that represents the payload to be signed - * @param prompt A string that needs to be displayed to the user in case user-auth is requested - * @param callback (error, signature) called after the transaction has been signed successfully or - * with an error and empty data when it fails - */ - fun signJwtBundle(context: Context, rootAddress: String, derivationPath: String, data: String, prompt: String, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - val (encryptionLayer, encryptedEntropy, storageError) = getEncryptionForLabel(context, asSeedLabel(rootAddress)) - - if (storageError != null) { - return callback(storageError, SignatureData()) - } - - encryptionLayer.decrypt(context, prompt, encryptedEntropy) { err, entropyBuff -> - if (err != null) { - return@decrypt callback(err, SignatureData()) - } - - try { - val phrase = entropyToMnemonic(entropyBuff, WORDLIST_ENGLISH) - val extendedKey = MnemonicWords(phrase).toKey(derivationPath) - - val keyPair = extendedKey.keyPair - - val payloadBytes = data.decodeBase64() - val sig = signJwt(payloadBytes, keyPair) - - return@decrypt callback(null, sig) - } catch (exception: Exception) { - return@decrypt callback(err, SignatureData()) - } - } - } - - /** - * Derives the ethereum address and public key using the given [derivationPath] starting from - * the seed that generated the given [rootAddress] - * - * The respective seed must have been previously generated or imported. - * - * The results are passed back to the calling code using the provided [callback] - */ - fun computeAddressForPath(context: Context, rootAddress: String, derivationPath: String, prompt: String, callback: (err: Exception?, address: String, pubKey: String) -> Unit) { - - val (encryptionLayer, encryptedEntropy, storageError) = getEncryptionForLabel(context, asSeedLabel(rootAddress)) - - if (storageError != null) { - return callback(storageError, "", "") - } - - encryptionLayer.decrypt(context, prompt, encryptedEntropy) { err, entropyBuff -> - if (err != null) { - return@decrypt callback(storageError, "", "") - } - - try { - val phrase = entropyToMnemonic(entropyBuff, WORDLIST_ENGLISH) - val extendedKey = MnemonicWords(phrase).toKey(derivationPath) - - val keyPair = extendedKey.keyPair - - val publicKeyBytes = keyPair.getUncompressedPublicKeyWithPrefix() - val publicKeyString = publicKeyBytes.toBase64().padBase64() - val address: String = keyPair.toAddress().hex - - return@decrypt callback(null, address, publicKeyString) - - } catch (exception: Exception) { - return@decrypt callback(err, "", "") - } - } - - - } - - /** - * Decrypts the seed that generated the given [rootAddress] and returns it as a mnemonic phrase - * - * The respective seed must have been previously generated or imported. - * - * The result is passed back to the calling code using the provided [callback] - */ - fun showHDSeed(context: Context, rootAddress: String, prompt: String, callback: (err: Exception?, phrase: String) -> Unit) { - - val (encryptionLayer, encryptedEntropy, storageError) = getEncryptionForLabel(context, asSeedLabel(rootAddress)) - - if (storageError != null) { - return callback(storageError, "") - } - - encryptionLayer.decrypt(context, prompt, encryptedEntropy) { err, entropyBuff -> - if (err != null) { - return@decrypt callback(err, "") - } - - try { - val phrase = entropyToMnemonic(entropyBuff, WORDLIST_ENGLISH) - return@decrypt callback(null, phrase) - } catch (exception: Exception) { - return@decrypt callback(err, "") - } - } - } - - /** - * Verifies if a given phrase is a valid mnemonic phrase usable in seed generation - */ - fun validateMnemonic(phrase: String): Boolean = MnemonicWords(phrase).validate(WORDLIST_ENGLISH) - - /** - * Returns a list of addresses representing the uport roots used as handles for seeds - */ - fun allHDRoots(context: Context): List { - - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - //list all stored keys, keep a list of what looks like uport root addresses - return prefs.all.keys - .asSequence() - .filter { label -> label.startsWith(SEED_PREFIX) } - .filter { hasCorrespondingLevelKey(prefs, it) } - .map { label: String -> label.substring(SEED_PREFIX.length) } - .toList() - } - - companion object { - const val UPORT_ROOT_DERIVATION_PATH = "m/7696500'/0'/0'/0'" - const val GENERIC_DEVICE_KEY_DERIVATION_PATH = "m/44'/60'/0'/0" - const val GENERIC_RECOVERY_DERIVATION_PATH = "m/44'/60'/0'/1" - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/UportHDSignerExtensions.kt b/signer/src/main/java/com/uport/sdk/signer/UportHDSignerExtensions.kt deleted file mode 100644 index dee0940d..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/UportHDSignerExtensions.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.uport.sdk.signer - -import android.content.Context -import com.uport.sdk.signer.encryption.KeyProtection -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -/** - * - * Exposes some HD key provider async methods as coroutines - */ - -suspend fun UportHDSigner.createHDSeed( - context: Context, - level: KeyProtection.Level): Pair = suspendCoroutine { - - this.createHDSeed(context, level) { err, address, pubKeyBase64 -> - if (err != null) { - it.resumeWithException(err) - } else { - it.resume(address to pubKeyBase64) - } - } -} - -suspend fun UportHDSigner.importHDSeed( - context: Context, - level: KeyProtection.Level, - phrase: String): Pair = suspendCoroutine { - - this.importHDSeed(context, level, phrase) { err, address, pubKeyBase64 -> - if (err != null) { - it.resumeWithException(err) - } else { - it.resume(address to pubKeyBase64) - } - } -} - -/** - * Extension function that wraps the `computeAddressForPath` as a coroutine - */ -suspend fun UportHDSigner.computeAddressForPath( - context: Context, - rootAddress: String, - derivationPath: String, - prompt: String): Pair = suspendCoroutine { - - this.computeAddressForPath(context, rootAddress, derivationPath, prompt) { err, address, pubKeyBase64 -> - if (err != null) { - it.resumeWithException(err) - } else { - it.resume(address to pubKeyBase64) - } - } -} - -suspend fun UportHDSigner.showHDSeed( - context: Context, - rootAddress: String, - prompt: String): String = suspendCoroutine { - - this.showHDSeed(context, rootAddress, prompt) { err, phrase -> - if (err != null) { - it.resumeWithException(err) - } else { - it.resume(phrase) - } - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/UportHDSignerImpl.kt b/signer/src/main/java/com/uport/sdk/signer/UportHDSignerImpl.kt deleted file mode 100644 index 3600e780..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/UportHDSignerImpl.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.uport.sdk.signer - -import android.content.Context -import com.uport.sdk.signer.UportHDSigner.Companion.UPORT_ROOT_DERIVATION_PATH -import me.uport.sdk.core.toBase64 -import org.kethereum.model.SignatureData - -/** - * Wraps a [UportHDSigner] into a [Signer] interface. - * - * The HD key provider it wraps needs an activity context for keys that are linked to user-auth. - * - * - * **This object should not be long-lived** - * - * FIXME: This implementation only uses the UPORT_ROOT_DERIVATION_PATH derivation path. The path should be a parameter and the resulting device address should be calculated after the key is unlocked. - */ -class UportHDSignerImpl( - private val context: Context, - private val uportHDSigner: UportHDSigner, - private val rootAddress: String, - private val deviceAddress: String -) : Signer { - - override fun signETH( - rawMessage: ByteArray, - callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - return uportHDSigner.signTransaction( - context, //FIXME: Not cool hiding the context like this... may lead to leaks - rootAddress, - UPORT_ROOT_DERIVATION_PATH, //FIXME: path should be configurable - rawMessage.toBase64(), - "", - callback) - } - - override fun signJWT(rawPayload: ByteArray, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - return uportHDSigner.signJwtBundle( - context, //FIXME: Not cool hiding the context like this... may lead to leaks - rootAddress, - UPORT_ROOT_DERIVATION_PATH, //FIXME: path should be configurable - rawPayload.toBase64(), - "", - callback) - } - - /** - * returns the address that corresponds to the device keypair - */ - override fun getAddress(): String = deviceAddress - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/UportSigner.kt b/signer/src/main/java/com/uport/sdk/signer/UportSigner.kt deleted file mode 100644 index b4c979f4..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/UportSigner.kt +++ /dev/null @@ -1,388 +0,0 @@ -@file:Suppress("TooManyFunctions") - -package com.uport.sdk.signer - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import android.content.SharedPreferences -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE -import com.uport.sdk.signer.encryption.KeyProtection -import com.uport.sdk.signer.encryption.KeyProtectionFactory -import com.uport.sdk.signer.encryption.SimpleAsymmetricProtection -import me.uport.sdk.core.decodeBase64 -import me.uport.sdk.core.padBase64 -import me.uport.sdk.core.toBase64 -import org.kethereum.crypto.createEthereumKeyPair -import org.kethereum.crypto.model.ECKeyPair -import org.kethereum.crypto.model.PRIVATE_KEY_SIZE -import org.kethereum.crypto.model.PUBLIC_KEY_SIZE -import org.kethereum.crypto.model.PrivateKey -import org.kethereum.crypto.signMessage -import org.kethereum.crypto.signMessageHash -import org.kethereum.crypto.toAddress -import org.kethereum.crypto.toECKeyPair -import org.kethereum.extensions.toBytesPadded -import org.kethereum.hashes.sha256 -import org.kethereum.model.SignatureData -import org.spongycastle.jce.provider.BouncyCastleProvider -import java.math.BigInteger -import java.security.InvalidKeyException -import java.security.KeyException -import java.security.Security - -@Suppress("unused") -open class UportSigner { - - init { - Security.addProvider(BouncyCastleProvider()) - } - - /** - * checks if the device is secured with a lockscreen - */ - fun hasSecuredKeyguard(context: Context, callback: (Boolean) -> Unit) { - val keyguardSecured = KeyProtection.canUseKeychainAuthentication(context) - callback(keyguardSecured) - } - - /** - * checks if the user has enrolled fingerprints - */ - fun hasSetupFingerprints(context: Context, callback: (Boolean) -> Unit) { - callback(KeyProtection.hasSetupFingerprint(context)) - } - - /** - * checks if the device has a fingerprint sensor - */ - fun hasFingerprintHardware(context: Context, callback: (Boolean) -> Unit) { - callback(KeyProtection.hasFingerprintHardware(context)) - } - - - /** - * Creates an ETH keypair and stores it at the [level] encryption level. - * then [callback] with the corresponding 0x `address` and base64 `public Key` - * or a non-null error in case something went wrong - */ - fun createKey(context: Context, level: KeyProtection.Level, callback: (err: Exception?, address: String, pubKey: String) -> Unit) { - - val privateKeyBytes = try { - val (privKey, _) = createEthereumKeyPair() - privKey.key.toBytesPadded(PRIVATE_KEY_SIZE) - } catch (exception: Exception) { - return callback(KeyException("ERR_CREATING_KEYPAIR", exception), "", "") - } - - return saveKey(context, level, privateKeyBytes, callback) - } - - /** - * Stores a given [privateKeyBytes] ByteArray at the provided [level] of encryption. - * - * Then calls back with the derived 0x `address` and base64 `public Key` - * or a non-null err in case something goes wrong - */ - fun saveKey(context: Context, level: KeyProtection.Level, privateKeyBytes: ByteArray, callback: (err: Exception?, address: String, pubKey: String) -> Unit) { - - val keyPair = PrivateKey(privateKeyBytes).toECKeyPair() - - val publicKeyBytes = keyPair.getUncompressedPublicKeyWithPrefix() - val publicKeyString = publicKeyBytes.toBase64().padBase64() - val address: String = keyPair.toAddress().hex - - val label = asAddressLabel(address) - - storeEncryptedPayload(context, - level, - label, - privateKeyBytes - ) { err, _ -> - - //empty memory - privateKeyBytes.fill(0) - - if (err != null) { - return@storeEncryptedPayload callback(err, "", "") - } - - return@storeEncryptedPayload callback(null, address, publicKeyString) - } - } - - /** - * deletes a key from storage - */ - fun deleteKey(context: Context, address: String) { - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - val label = asAddressLabel(address) - prefs.edit() - .remove(label) - .remove(asLevelLabel(label)) - .apply() - } - - /** - * Signs a transaction bundle using the private key that generated the given address. - * In case the private key corresponding to the [address] requires user authentication to decrypt, - * this method will launch the decryption UI with a [prompt] and schedule a callback with the signature data - * after the decryption takes place or a non-null error in case something goes wrong (or user cancels) - * - * The decryption UI can be a device lockscreen or fingerprint-dialog depending on the level of encryption - * requested at key creation. - * - * @param context The android activity from which the signature is requested or app context if it's encrypted using [KeyProtection.Level.SIMPLE]] protection - * @param address the 0x ETH address corresponding to the desired key - * @param txPayload the base64 encoded byte array that represents the message to be signed - * @param prompt A string that needs to be displayed to the user in case fingerprint auth is requested - * @param callback (error, signature) called after the transaction has been signed successfully or - * with an error and empty data when it fails - */ - fun signTransaction(context: Context, address: String, txPayload: String, prompt: String, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - val (encryptionLayer, encryptedPrivateKey, storageError) = getEncryptionForLabel(context, asAddressLabel(address)) - - if (storageError != null) { - return callback(storageError, EMPTY_SIGNATURE_DATA) - } - - encryptionLayer.decrypt(context, prompt, encryptedPrivateKey) { err, privateKeyBytes -> - - if (err != null) { - return@decrypt callback(err, EMPTY_SIGNATURE_DATA) - } - - try { - val keyPair = PrivateKey(privateKeyBytes).toECKeyPair() - privateKeyBytes.fill(0) - - val txBytes = txPayload.decodeBase64() - - val sigData = keyPair.signMessage(txBytes) - return@decrypt callback(null, sigData) - - } catch (exception: Exception) { - return@decrypt callback(exception, EMPTY_SIGNATURE_DATA) - } - - } - - } - - /** - * Fetches the encryption combo for a particular label(address) - * The encryption combo is the ciphertext along with the class needed to decrypt it - */ - fun getEncryptionForLabel(context: Context, label: String): EncryptionCombo { - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - - return try { - //check if label is tracked - val keyExists = (prefs.contains(asLevelLabel(label)) - && prefs.contains(label)) - - if (!keyExists) { - throw InvalidKeyException(ERR_KEY_NOT_REGISTERED) - } - - val levelName = prefs.getString(asLevelLabel(label), null) ?: "" - val level = KeyProtection.Level.valueOf(levelName) - val encryptionLayer = KeyProtectionFactory.obtain(context, level) - - //read encrypted payload from storage - val encryptedPayload = prefs.getString(label, null) - ?: throw InvalidKeyException(ERR_KEY_CORRUPTED) - - EncryptionCombo(encryptionLayer, encryptedPayload, null) - - } catch (ex: Exception) { - EncryptionCombo(SimpleAsymmetricProtection(), "", ex) - } - } - - /** - * Signs a jwt payload using the private key that generated the given [address]. - * - * In case the private key corresponding to the [address] requires user authentication to decrypt, - * this method will launch the decryption UI and schedule a callback with the signature - * after the decryption takes place or a non-null error in case something goes wrong (or user cancels) - * - * The decryption UI can be a device lockscreen or fingerprint-dialog depending on the - * [KeyProtection.Level] of encryption requested at key creation. - * - * @param context The android activity from which the signature is requested or application context; - * @param address the 0x ETH address corresponding to the desired key - * @param data the base64 encoded byte array that represents the message to be signed - * @param prompt A string that needs to be displayed to the user in case fingerprint auth is requested - * @param callback (error, signature) called after the transaction has been signed successfully or - * with an error and empty data when it fails - */ - fun signJwtBundle(context: Context, address: String, data: String, prompt: String, callback: (err: Exception?, sigData: SignatureData) -> Unit) { - - val (encryptionLayer, encryptedPrivateKey, storageError) = getEncryptionForLabel(context, asAddressLabel(address)) - - if (storageError != null) { - return callback(storageError, SignatureData()) - } - - encryptionLayer.decrypt(context, prompt, encryptedPrivateKey) { err, privateKeyBytes -> - if (err != null) { - return@decrypt callback(err, SignatureData()) - } - - try { - val keyPair = PrivateKey(privateKeyBytes).toECKeyPair() - val payloadBytes = data.decodeBase64() - val sig = signJwt(payloadBytes, keyPair) - privateKeyBytes.fill(0) - - return@decrypt callback(null, sig) - } catch (exception: Exception) { - return@decrypt callback(err, SignatureData()) - } - } - } - - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) - fun signJwt(payloadBytes: ByteArray, keyPair: ECKeyPair) = signMessageHash(payloadBytes.sha256(), keyPair, false) - - /** - * Builds a list of all the saved eth addresses (that also have encrypted private keys tracked) - */ - fun allAddresses(context: Context, callback: (addresses: List) -> Unit) { - - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - //list all stored keys, keep a list of what looks like addresses - val addresses = prefs.all.keys - .filter { label -> label.startsWith(ADDRESS_PREFIX) } - .filter { hasCorrespondingLevelKey(prefs, it) } - .map { label: String -> label.substring(ADDRESS_PREFIX.length) } - callback(addresses) - } - - /** - * Stores the given [payload] ByteArray encrypted at the provided [keyLevel]. - * The encrypted [payload] and corresponding [keyLevel] can later be retrieved using the [label] - * - * This method calls back with the success of the encryption operation - * or a non-null exception if something goes wrong - */ - fun storeEncryptedPayload( - context: Context, - keyLevel: KeyProtection.Level, - label: String, - payload: ByteArray, - callback: (err: Exception?, result: Boolean) -> Unit - ) { - - try { - val encLayer: KeyProtection = KeyProtectionFactory.obtain(context, keyLevel) - val prefs = context.getSharedPreferences(ETH_ENCRYPTED_STORAGE, MODE_PRIVATE) - - encLayer.encrypt( - context, - "store encrypted payload", - payload - ) { err, ciphertext -> - - if (err != null) { - return@encrypt callback(err, false) - } - prefs.edit() - //store encrypted privatekey - .putString(label, ciphertext) - //mark the key as encrypted with provided security level - .putString(asLevelLabel(label), keyLevel.name) - .apply() - return@encrypt callback(null, true) - } - } catch (ex: Exception) { - return callback(ex, false) - } - } - - /** - * Decrypts a previously encrypted payload that was stored under the given [label] - * - * Payloads can be stored at different levels of encryption (see [storeEncryptedPayload]) - * In case the payload in question needs user presence to decrypt, - * the [context] should be an instance of AppcompatActivity and it will - * show the necessary UI (fingerprint dialog or lock-screen) with a [prompt] - * - * This method calls back with the decrypted [ByteArray] on success - * or a non-null exception if something goes wrong - */ - fun loadEncryptedPayload( - context: Context, - label: String, - prompt: String, - callback: (err: Exception?, result: ByteArray) -> Unit - ) { - - val (encryptionLayer, encryptedPayload, storageError) = getEncryptionForLabel(context, label) - - if (storageError != null) { - return callback(storageError, ByteArray(0)) - } - - //decrypt using the appropriate level - encryptionLayer.decrypt(context, prompt, encryptedPayload) { err, decrypted -> - if (err != null) { - return@decrypt callback(err, ByteArray(0)) - } - - return@decrypt callback(null, decrypted) - } - } - - companion object { - - internal const val ETH_ENCRYPTED_STORAGE = "eth_signer_store" - - private const val ADDRESS_PREFIX = "address-" - internal const val SEED_PREFIX = "seed-" - - val asLevelLabel = { what: String -> "level-$what" } - val asAddressLabel = { address: String -> "$ADDRESS_PREFIX$address" } - val asGenericLabel = { label: String -> "enc-$label" } - val asSeedLabel = { label: String -> "$SEED_PREFIX$label" } - - val hasCorrespondingLevelKey = { prefs: SharedPreferences, label: String -> prefs.contains(asLevelLabel(label)) } - - /** - * This is thrown by KeyguardProtection when the user has not configured any device security. - * Prompt the user to setup PIN / Pattern / Password protection for their device. - * You can use Intent(Settings.ACTION_SECURITY_SETTINGS) to lead them to Android Settings -> Security tab - */ - const val ERR_KEYGUARD_NOT_CONFIGURED = "E_KEYGUARD_NOT_CONFIGURED" - - /** - * Thrown when trying to encrypt/decrypt something with a key that is not registered - */ - const val ERR_KEY_NOT_REGISTERED = "E_KEY_NOT_REGISTERED" - const val ERR_KEY_CORRUPTED = "E_KEY_CORRUPTED" - const val ERR_BLANK_KEY = "E_BLANK_KEY" - const val ERR_ENCODING_ERROR = "E_ENCODING_PROBLEM" - const val ERR_AUTH_CANCELED = "E_AUTH_CANCELED" - - /** - * Thrown when the [KeyProtection.Level] requested is [KeyProtection.Level.SINGLE_PROMPT] or [KeyProtection.Level.PROMPT] - * but the requested operation is being performed outside an activity context. - * - * For signing stuff with these protection levels, an activity is needed to launch the proper UI. - */ - const val ERR_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST" - - const val UNCOMPRESSED_PUBLIC_KEY_SIZE = PUBLIC_KEY_SIZE + 1 - const val COMPRESSED_PUBLIC_KEY_SIZE = PRIVATE_KEY_SIZE + 1 - - data class EncryptionCombo(val keyProtection: KeyProtection, val encPayload: String, val err: Exception?) - - internal val EMPTY_SIGNATURE_DATA = SignatureData(BigInteger.ZERO, BigInteger.ZERO, 0) - - } - -} - - diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/AndroidKeyStoreHelper.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/AndroidKeyStoreHelper.kt deleted file mode 100644 index be46c8b1..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/AndroidKeyStoreHelper.kt +++ /dev/null @@ -1,155 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer.encryption - -import android.annotation.SuppressLint -import android.content.Context -import android.os.Build -import android.security.KeyPairGeneratorSpec -import android.security.keystore.KeyGenParameterSpec -import android.security.keystore.KeyPermanentlyInvalidatedException -import android.security.keystore.KeyProperties -import com.uport.sdk.signer.hasMarshmallow -import java.io.IOException -import java.math.BigInteger -import java.security.* -import java.security.spec.MGF1ParameterSpec -import java.security.spec.RSAKeyGenParameterSpec -import java.security.spec.X509EncodedKeySpec -import java.util.* -import javax.crypto.Cipher -import javax.crypto.NoSuchPaddingException -import javax.crypto.spec.OAEPParameterSpec -import javax.crypto.spec.PSource -import javax.security.auth.x500.X500Principal -import javax.security.cert.CertificateException - -object AndroidKeyStoreHelper { - - const val ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore" - - /** - * Size of the RSA key used to wrap the protected key - */ - private const val WRAPPING_KEY_SIZE = 2048 - - /** - * [java.security.spec.AlgorithmParameterSpec] applied to the wrapping cipher on API 23+ - */ - private val OAEP_SPEC = OAEPParameterSpec( - "SHA-256", "MGF1", - MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT) - - /** - * The cipher transformation used to wrap the protected key - */ - private val WRAPPING_TRANSFORMATION = - if (hasMarshmallow()) - "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" - else - "RSA/ECB/PKCS1Padding" - - - @Throws(KeyStoreException::class, - NoSuchProviderException::class, - IOException::class, - NoSuchAlgorithmException::class, - CertificateException::class) - internal fun getKeyStore(): KeyStore { - // Get a KeyStore instance with the Android Keystore provider. - val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER) - - // Relict of the old JCA API - you have to call load() even - // if you do not have an input stream you want to load - otherwise it'll crash. - keyStore.load(null) - return keyStore - } - - @Throws(KeyPermanentlyInvalidatedException::class, - KeyStoreException::class, - CertificateException::class, - UnrecoverableKeyException::class, - IOException::class, - NoSuchAlgorithmException::class, - InvalidKeyException::class, - InvalidAlgorithmParameterException::class, - NoSuchProviderException::class, - NoSuchPaddingException::class) - fun getWrappingCipher(mode: Int, keyAlias: String): Cipher { - - val keyStore = getKeyStore() - - val cipher = Cipher.getInstance(WRAPPING_TRANSFORMATION) - - val key = when (mode) { - Cipher.DECRYPT_MODE, Cipher.UNWRAP_MODE -> { - keyStore.getKey(keyAlias, null) as PrivateKey - } - //ENCRYPT_MODE, WRAP_MODE - else -> { - val pubKey = keyStore.getCertificate(keyAlias).publicKey - //due to a bug in API23, the public key needs to be separated from the keystore - KeyFactory.getInstance(pubKey.algorithm) - .generatePublic(X509EncodedKeySpec(pubKey.encoded)) as PublicKey - } - } - - if (hasMarshmallow()) { - cipher.init(mode, key, OAEP_SPEC) - } else { - cipher.init(mode, key) - } - - return cipher - } - - @SuppressLint("NewApi") - @Throws(KeyStoreException::class, - NoSuchProviderException::class, - NoSuchAlgorithmException::class, - InvalidAlgorithmParameterException::class) - fun generateWrappingKey(context: Context, keyAlias: String, requiresAuth: Boolean = false, sessionTimeout: Int = -1) { - - val keyStore = getKeyStore() - val publicKey = keyStore.getCertificate(keyAlias)?.publicKey - - if (publicKey == null) { - - val spec = if (hasMarshmallow()) { - KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_DECRYPT) - .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP) - .setUserAuthenticationRequired(requiresAuth) - .setUserAuthenticationValidityDurationSeconds(sessionTimeout) - .build() - } else { - val cal = Calendar.getInstance() - val startDate: Date = cal.time - cal.add(Calendar.YEAR, 100) - val endDate: Date = cal.time - - @Suppress("DEPRECATION") - val specBuilder = KeyPairGeneratorSpec.Builder(context) - .setAlias(keyAlias) - .setSubject(X500Principal("CN=$keyAlias")) - .setSerialNumber(BigInteger.ONE) - .setStartDate(startDate) - .setEndDate(endDate) - // Only API levels 19 and above allow specifying RSA key parameters. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - val rsaSpec = RSAKeyGenParameterSpec(WRAPPING_KEY_SIZE, RSAKeyGenParameterSpec.F4) - specBuilder.setAlgorithmParameterSpec(rsaSpec) - specBuilder.setKeySize(WRAPPING_KEY_SIZE) - } - if (requiresAuth) { - specBuilder.setEncryptionRequired() - } - specBuilder.build() - } - - val keyPairGenerator = KeyPairGenerator.getInstance("RSA", ANDROID_KEYSTORE_PROVIDER) - keyPairGenerator.initialize(spec) - keyPairGenerator.generateKeyPair() - } - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintAsymmetricProtection.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintAsymmetricProtection.kt deleted file mode 100644 index 4e3f034e..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintAsymmetricProtection.kt +++ /dev/null @@ -1,94 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer.encryption - -import android.annotation.TargetApi -import android.content.Context -import android.hardware.fingerprint.FingerprintManager -import android.os.Build -import android.support.v4.app.DialogFragment -import android.support.v7.app.AppCompatActivity -import com.uport.sdk.signer.* -import com.uport.sdk.signer.UportSigner.Companion.ERR_ACTIVITY_DOES_NOT_EXIST -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.generateWrappingKey -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.getWrappingCipher -import javax.crypto.Cipher - -class FingerprintAsymmetricProtection : KeyProtection() { - - override - val alias = "__fingerprint_asymmetric_key_alias__" - - override - fun genKey(context: Context) { - - generateWrappingKey(context, alias, true) - } - - override - fun encrypt(context: Context, purpose: String, blob: ByteArray, callback: EncryptionCallback) { - try { - val ciphertext = encryptRaw(blob, alias) - callback(null, ciphertext) - } catch (ex: Exception) { - callback(ex, "") - } - } - - @TargetApi(Build.VERSION_CODES.M) - override - fun decrypt(context: Context, purpose: String, ciphertext: String, callback: DecryptionCallback) { - - try { - val (_, encryptedBytes) = unpackCiphertext(ciphertext) - - val cipher = getWrappingCipher(Cipher.DECRYPT_MODE, alias) - - if (context is AppCompatActivity) { - showFingerprintDialog(context, purpose, cipher) { err, cryptoObject -> - if (err != null) { - callback(err, ByteArray(0)) - } else { - val cleartextBytes = cryptoObject.cipher.doFinal(encryptedBytes) - callback(null, cleartextBytes) - } - } - } else { - callback(IllegalStateException(ERR_ACTIVITY_DOES_NOT_EXIST), ByteArray(0)) - } - } catch (ex: Exception) { - callback(ex, ByteArray(0)) - } - } - - - private lateinit var fingerprintDialog: FingerprintDialog - - @TargetApi(Build.VERSION_CODES.M) - private fun showFingerprintDialog(activity: AppCompatActivity, purpose: String, cipher: Cipher, callback: (err: Exception?, FingerprintManager.CryptoObject) -> Unit) { - - fingerprintDialog = FingerprintDialog.create(purpose) - fingerprintDialog.setStyle(DialogFragment.STYLE_NO_TITLE, R.style.uport_AppDialogTheme) - - if (activity.fragmentManager.findFragmentByTag(FingerprintDialog.TAG_FINGERPRINT_DIALOG) == null) { - val cryptoObject = FingerprintManager.CryptoObject(cipher) - fingerprintDialog.init( - cryptoObject, - object : FingerprintDialog.FingerprintDialogCallbacks { - override fun onFingerprintSuccess(cryptoObject: FingerprintManager.CryptoObject) { - callback(null, cryptoObject) - fingerprintDialog.dismiss() - } - - override fun onFingerprintCancel() { - callback(RuntimeException(UportSigner.ERR_AUTH_CANCELED), cryptoObject) - fingerprintDialog.dismiss() - } - - } - ) - fingerprintDialog.show(activity.supportFragmentManager, FingerprintDialog.TAG_FINGERPRINT_DIALOG) - } - } - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintDialog.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintDialog.kt deleted file mode 100644 index d7ce1839..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/FingerprintDialog.kt +++ /dev/null @@ -1,225 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer.encryption - -import android.animation.Animator -import android.annotation.TargetApi -import android.content.Context -import android.graphics.Color -import android.hardware.fingerprint.FingerprintManager -import android.os.Build -import android.os.Bundle -import android.os.CancellationSignal -import android.support.v4.app.DialogFragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.animation.DecelerateInterpolator -import android.view.animation.OvershootInterpolator -import android.widget.ImageView -import android.widget.TextView -import com.uport.sdk.signer.R - -@TargetApi(Build.VERSION_CODES.M) -class FingerprintDialog : DialogFragment() { - - private lateinit var fingerprintManager: FingerprintManager - private lateinit var cancellationSignal: CancellationSignal - private lateinit var cryptoObject: FingerprintManager.CryptoObject - private lateinit var callbacks: FingerprintDialogCallbacks - private lateinit var purpose: String - - private lateinit var purposeTextView: TextView - private lateinit var imageViewStatus: ImageView - private lateinit var textViewStatus: TextView - private lateinit var cancelButton: View - - private var successColor: Int = 0 - private var failureColor: Int = 0 - - override - fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - retainInstance = true - - purpose = savedInstanceState?.getString(KEY_DIALOG_PURPOSE) ?: arguments?.getString(KEY_DIALOG_PURPOSE) ?: "" - - fingerprintManager = context?.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager - successColor = context?.getColor(R.color.uport_fingerprint_green) ?: Color.GREEN - failureColor = context?.getColor(R.color.uport_fingerprint_red) ?: Color.RED - } - - override - fun onStart() { - super.onStart() - // Reset the cancellation signal which is used to cancel the - // fingerprint authentication process. - cancellationSignal = CancellationSignal() - - // Check if a valid CryptoObject has been provided - try { - // Start listening for fingerprint events - fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, AuthCallbacks(), null) - } catch (e: IllegalArgumentException) { - // Should never be thrown since we have declared the USE_FINGERPRINT permission - // in the manifest - } catch (e: IllegalStateException) { - //nop - } catch (e: SecurityException) { - //nop - } - } - - override - fun onStop() { - super.onStop() - - // If the fingerprint authentication process is running, cancel it. - cancellationSignal.cancel() - } - - override - fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val content = inflater.inflate(R.layout.fragment_fingerprint, container) - - purposeTextView = content.findViewById(R.id.purpose) - purposeTextView.text = purpose - imageViewStatus = content.findViewById(R.id.imageViewFingerprintStatus) - textViewStatus = content.findViewById(R.id.textViewFingerprintStatus) - cancelButton = content.findViewById(R.id.buttonFingerprintCancel) - - cancelButton.setOnClickListener { onCancelPressed() } - - return content - } - - override - fun onDestroyView() { - val dialog = dialog - // handles https://code.google.com/p/android/issues/detail?id=17423 - if (dialog != null && retainInstance) { - dialog.setDismissMessage(null) - } - super.onDestroyView() - } - - private fun onCancelPressed() { - callbacks.onFingerprintCancel() - dismiss() - } - - /** - * Should be called before the dialog is shown in order to provide a valid CryptoObject. - * - * @param cryptoObject The [FingerprintManager.CryptoObject] we want to authenticate for - * @param callbacks an implementation of the [FingerprintDialogCallbacks] interface - */ - fun init(cryptoObject: FingerprintManager.CryptoObject, callbacks: FingerprintDialogCallbacks) { - this.cryptoObject = cryptoObject - this.callbacks = callbacks - } - - /** - * Updates the status text in the dialog with the provided error message. - * - * @param text represents the error message which will be shown - */ - private fun showErrorText(text: CharSequence) { - imageViewStatus.setImageResource(R.drawable.uport_ic_fingerprint_error) - textViewStatus.text = text - textViewStatus.setTextColor(failureColor) - - imageViewStatus.animate() - .rotationBy(90f) - .setInterpolator(OvershootInterpolator(1.4f)).duration = ANIMATION_DURATION.toLong() - } - - /** - * Updates the status text in the dialog with a success text. - */ - private fun showSuccessText() { - imageViewStatus.setImageResource(R.drawable.uport_ic_fingerprint_done) - textViewStatus.text = getString(R.string.uport_fingerprint_success) - textViewStatus.setTextColor(successColor) - - imageViewStatus.rotation = 60f - imageViewStatus.animate() - .rotation(0f) - .setInterpolator(DecelerateInterpolator(1.4f)) - .setDuration(ANIMATION_DURATION.toLong()) - .setListener(object : Animator.AnimatorListener { - override fun onAnimationStart(animation: Animator) { - // Empty - } - - override fun onAnimationEnd(animation: Animator) { - // Wait for the animation to finish, then dismiss the dialog and - // invoke the callback method - callbacks.onFingerprintSuccess(cryptoObject) - dismiss() - } - - override fun onAnimationCancel(animation: Animator) { - // Empty - } - - override fun onAnimationRepeat(animation: Animator) { - // Empty - } - }) - } - - /** - * The interface which the caller must implement - */ - interface FingerprintDialogCallbacks { - - fun onFingerprintSuccess(cryptoObject: FingerprintManager.CryptoObject) - - fun onFingerprintCancel() - } - - /** - * This class represents the callbacks invoked by the FingerprintManager class. - */ - inner class AuthCallbacks : FingerprintManager.AuthenticationCallback() { - - override fun onAuthenticationFailed() { - super.onAuthenticationFailed() - showErrorText("Authentication failed") - } - - override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { - super.onAuthenticationError(errorCode, errString) - //TODO: if "too many attempts error occurs, ask for device unlock" - showErrorText(errString) - } - - override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) { - super.onAuthenticationHelp(helpCode, helpString) - showErrorText(helpString) - } - - override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { - super.onAuthenticationSucceeded(result) - showSuccessText() - } - } - - companion object { - - const val ANIMATION_DURATION = 500 - const val KEY_DIALOG_PURPOSE = "key_purpose" - const val TAG_FINGERPRINT_DIALOG: String = "fingerprint_dialog" - - fun create(purpose: String): FingerprintDialog { - val dialog = FingerprintDialog() - val bundle = Bundle() - bundle.putString(KEY_DIALOG_PURPOSE, purpose) - dialog.arguments = bundle - return dialog - } - - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtection.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtection.kt deleted file mode 100644 index ec8a7036..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtection.kt +++ /dev/null @@ -1,118 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer.encryption - -import android.annotation.SuppressLint -import android.app.KeyguardManager -import android.content.Context -import android.hardware.fingerprint.FingerprintManager -import com.uport.sdk.signer.* -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.getWrappingCipher -import javax.crypto.BadPaddingException -import javax.crypto.Cipher.DECRYPT_MODE -import javax.crypto.Cipher.ENCRYPT_MODE -import javax.crypto.IllegalBlockSizeException - - -/** - * Describes the functionality of encryption layer - */ -abstract class KeyProtection { - - enum class Level { - /** - * Requires user authentication within a 30 second time window - */ - SINGLE_PROMPT, - - /** - * Requires user authentication using fingerprint or Lockscreen for every use of the key - */ - PROMPT, - - /** - * Uses AndroidKeyStore encryption, without user presence requirement - */ - SIMPLE, - - /** - * unused yet - defaults to [SIMPLE] - */ - CLOUD - } - - abstract fun genKey(context: Context) - abstract fun encrypt(context: Context, purpose: String = "", blob: ByteArray, callback: EncryptionCallback) - abstract fun decrypt(context: Context, purpose: String = "", ciphertext: String, callback: DecryptionCallback) - - abstract val alias: String - - companion object { - - fun canUseKeychainAuthentication(context: Context): Boolean { - val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - // TODO: prompt user to setup keyguard - return keyguardManager.isKeyguardSecure - } - - @SuppressLint("NewApi") - fun hasSetupFingerprint(context: Context): Boolean { - if (hasMarshmallow()) { - val mFingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager - try { - if (!mFingerprintManager.isHardwareDetected) { - return false - } else if (!mFingerprintManager.hasEnrolledFingerprints()) { - //TODO: prompt user to enroll fingerprints - return false - } - } catch (e: SecurityException) { - // Should never be thrown since we have declared the USE_FINGERPRINT permission - // in the manifest file - return false - } - - return true - } else { - return false - } - } - - @SuppressLint("NewApi") - fun hasFingerprintHardware(context: Context): Boolean { - return if (hasMarshmallow()) { - val mFingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager - try { - mFingerprintManager.isHardwareDetected - } catch (e: SecurityException) { - // Should never be thrown since we have declared the USE_FINGERPRINT permission - // in the manifest file - false - } - } else { - false - } - } - - @Throws(IllegalBlockSizeException::class, BadPaddingException::class) - internal fun encryptRaw(blob: ByteArray, keyAlias: String): String { - - val cipher = getWrappingCipher(ENCRYPT_MODE, keyAlias) - - val encryptedBytes = cipher.doFinal(blob) - - val ivCompat = ByteArray(0) - return packCiphertext(ivCompat, encryptedBytes) - } - - @Throws(IllegalBlockSizeException::class, BadPaddingException::class) - internal fun decryptRaw(ciphertext: String, keyAlias: String): ByteArray { - - val cipher = getWrappingCipher(DECRYPT_MODE, keyAlias) - - val (_, encryptedBytes) = unpackCiphertext(ciphertext) - - return cipher.doFinal(encryptedBytes) - } - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtectionFactory.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtectionFactory.kt deleted file mode 100644 index e6c06980..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyProtectionFactory.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.uport.sdk.signer.encryption - -import android.content.Context -import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP - -/** - * Exposes a method of obtaining a [KeyProtection] implementation based on a required level - */ -object KeyProtectionFactory { - - /** - * returns a [KeyProtection] implementation based on the provided [level] - * - * The method requires an Application [context] that will be used to determine device security - * capabilities and to initialize key stores when needed. - */ - @Suppress("ComplexMethod") - fun obtain(context: Context, level: KeyProtection.Level): KeyProtection { - - val apiAdjustedLevel = if (Build.VERSION.SDK_INT >= LOLLIPOP) { - level - } else { - //only simple protection is available for KitKat - KeyProtection.Level.SIMPLE - } - - val store = when (apiAdjustedLevel) { - - KeyProtection.Level.SINGLE_PROMPT -> { - KeyguardAsymmetricProtection() - } - - KeyProtection.Level.PROMPT -> { - - if (KeyProtection.hasSetupFingerprint(context)) { - FingerprintAsymmetricProtection() - } else { - val sessionTime = if (KeyProtection.hasFingerprintHardware(context)) { - 0 // pop keyguard with 0 second authentication window (practically for every use) - - /** - * reason for this behavior: - * - * on devices that have fingerprint hardware but haven't setup fingerprints - * an IllegalBlockSizeException is thrown if the requested session time is "-1" - * with the cause being KeyStoreException("Key user not authenticated") - * - * Therefore, we emulate this by a 0 second authentication window - */ - } else { - -1 // pop keyguard for every use - } - KeyguardAsymmetricProtection(sessionTime) - } - } - - KeyProtection.Level.SIMPLE -> { - SimpleAsymmetricProtection() - } - - else -> { - SimpleAsymmetricProtection() - } - } - //ensure store is setup - store.genKey(context) - return store - } - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardAsymmetricProtection.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardAsymmetricProtection.kt deleted file mode 100644 index a0441ef8..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardAsymmetricProtection.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.uport.sdk.signer.encryption - -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Context -import android.security.keystore.UserNotAuthenticatedException -import android.support.v7.app.AppCompatActivity -import com.uport.sdk.signer.DecryptionCallback -import com.uport.sdk.signer.EncryptionCallback -import com.uport.sdk.signer.UportSigner -import com.uport.sdk.signer.UportSigner.Companion.ERR_ACTIVITY_DOES_NOT_EXIST -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.generateWrappingKey -import com.uport.sdk.signer.hasMarshmallow -import java.security.InvalidKeyException - -class KeyguardAsymmetricProtection(sessionTimeoutSeconds: Int = DEFAULT_SESSION_TIMEOUT_SECONDS) : KeyProtection() { - - override - val alias = "__keyguard_asymmetric_key_alias__" - - private var sessionTimeout: Int = sessionTimeoutSeconds - private val extendedAlias = if (sessionTimeout == DEFAULT_SESSION_TIMEOUT_SECONDS) { - alias - } else { - "$alias$sessionTimeout" - } - - override - fun genKey(context: Context) { - - if (!KeyProtection.canUseKeychainAuthentication(context)) { - throw IllegalStateException(UportSigner.ERR_KEYGUARD_NOT_CONFIGURED) - } - - generateWrappingKey(context, extendedAlias, true, sessionTimeout) - } - - override - fun encrypt(context: Context, purpose: String, blob: ByteArray, callback: EncryptionCallback) { - try { - val ciphertext = KeyProtection.encryptRaw(blob, extendedAlias) - callback(null, ciphertext) - } catch (ex: Exception) { - callback(ex, "") - } - } - - /** - * Emulates a keyguard protected key on API 19-22 - * - * On API 19-22, keys don't throw UserNotAuthenticatedException while the screen is unlocked - * so that behavior needs to be emulated - */ - private fun shouldShowKeyguard(): Boolean { - val now = System.currentTimeMillis() - val elapsedTimeMillis = (now - getLastUnlock(extendedAlias)) - return if (sessionTimeout >= 0) { - elapsedTimeMillis > sessionTimeout * 1000 - } else { - true - } - } - - - private fun decryptAfterKeyguard(context: Context, purpose: String, ciphertext: String, callback: DecryptionCallback) { - if (context is AppCompatActivity) { - showKeyguard( - context, - purpose, - object : KeyguardLaunchFragment.KeyguardCallback { - override fun onKeyguardResult(unlocked: Boolean) { - if (unlocked) { - try { - val cleartextBytes = KeyProtection.decryptRaw(ciphertext, extendedAlias) - //only update if there was no exception - updateUnlock(extendedAlias) - //finally decrypted.. phew - callback(null, cleartextBytes) - } catch (exception: Exception) { - callback(exception, ByteArray(0)) - } - } else { - callback(RuntimeException(UportSigner.ERR_AUTH_CANCELED), ByteArray(0)) - } - } - }) - } else { - callback(IllegalStateException(ERR_ACTIVITY_DOES_NOT_EXIST), ByteArray(0)) - } - } - - @Suppress("NestedBlockDepth", "ComplexMethod") - override - fun decrypt(context: Context, purpose: String, ciphertext: String, callback: DecryptionCallback) { - try { - if (hasMarshmallow()) { - try { - val cleartextBytes = KeyProtection.decryptRaw(ciphertext, extendedAlias) - callback(null, cleartextBytes) - } catch (exception: InvalidKeyException) { - @SuppressLint("NewApi") - if (exception is UserNotAuthenticatedException) { - decryptAfterKeyguard(context, purpose, ciphertext, callback) - } else { - throw exception - } - } - } else { - if (shouldShowKeyguard()) { - decryptAfterKeyguard(context, purpose, ciphertext, callback) - } else { - val cleartextBytes = KeyProtection.decryptRaw(ciphertext, extendedAlias) - callback(null, cleartextBytes) - } - } - } catch (exception: Exception) { - //TODO: possible scenario to address: if the device has just configured PIN and has never been unlocked, this may throw IllegalBlockSizeException - return callback(exception, ByteArray(0)) - } - } - - private fun showKeyguard(activity: Activity, purpose: String, callback: KeyguardLaunchFragment.KeyguardCallback) { - val supportFragmentManager = (activity as AppCompatActivity).supportFragmentManager - KeyguardLaunchFragment.show(supportFragmentManager, purpose, callback) - } - - - companion object { - private const val DEFAULT_SESSION_TIMEOUT_SECONDS: Int = 30 //seconds - - private val lastUnlock = mapOf().toMutableMap() - - @Synchronized - private fun getLastUnlock(alias: String): Long { - return lastUnlock[alias] ?: 0L - } - - @Synchronized - private fun updateUnlock(alias: String) { - lastUnlock[alias] = System.currentTimeMillis() - } - - } - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardLaunchFragment.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardLaunchFragment.kt deleted file mode 100644 index e1030593..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/KeyguardLaunchFragment.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.uport.sdk.signer.encryption - -import android.annotation.SuppressLint -import android.app.Activity -import android.app.KeyguardManager -import android.content.Context.KEYGUARD_SERVICE -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentManager -import com.uport.sdk.signer.hasMarshmallow - -class KeyguardLaunchFragment : Fragment() { - - private lateinit var keyguardManager: KeyguardManager - private lateinit var callback: KeyguardCallback - private lateinit var purpose: String - - override - fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - retainInstance = true - keyguardManager = context?.getSystemService(KEYGUARD_SERVICE) as KeyguardManager - - val keyguardIntent = createConfirmDeviceCredentialIntent("uPort", purpose) - startActivityForResult(keyguardIntent, REQUEST_CODE_KEYGUARD) - } - - /** - * Pops up the keyguard with the corresponding text. - * On API 23+, this is needed to unlock keys that have been created with [setRequiresAuthentication(true)] - */ - @SuppressLint("NewApi") - private fun createConfirmDeviceCredentialIntent(title: String, description: String): Intent { - return if (hasMarshmallow()) { - keyguardManager.createConfirmDeviceCredentialIntent(title, description) - } else { - val action = "android.app.action.CONFIRM_DEVICE_CREDENTIAL" - val keyguardIntent = Intent(action) - keyguardIntent.putExtra("android.app.extra.DESCRIPTION", description) - - keyguardIntent.putExtra("android.app.extra.TITLE", "$title\n\n$description") - keyguardIntent.setPackage(getSettingsPackageForIntent(keyguardIntent)) - - keyguardIntent - } - } - - /** - * based on AOSP KeyguardManager.java for API 23+ - */ - @SuppressLint("InlinedApi") - private fun getSettingsPackageForIntent(intent: Intent): String { - val ctx = context - if (ctx != null) { - val resolveInfos = ctx.packageManager - .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY) - for (i in resolveInfos.indices) { - return resolveInfos[i].activityInfo.packageName - } - } - return "com.android.settings" - } - - private fun init(purpose: String, callback: KeyguardCallback) { - this.callback = callback - this.purpose = purpose - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == REQUEST_CODE_KEYGUARD) { - val result = resultCode == Activity.RESULT_OK - callback.onKeyguardResult(result) - dismiss() - } - } - - private fun dismiss() { - fragmentManager?.beginTransaction()?.remove(this)?.commit() - } - - interface KeyguardCallback { - fun onKeyguardResult(unlocked: Boolean) - } - - companion object { - - private const val TAG_KEYGUARD_FRAGMENT: String = "keyguard_fragment" - private const val REQUEST_CODE_KEYGUARD: Int = 19867 - - fun show(fragManager: FragmentManager, purpose: String, callback: KeyguardCallback) { - - //cleanup.. - val headlessFragment = fragManager.findFragmentByTag(TAG_KEYGUARD_FRAGMENT) as KeyguardLaunchFragment? - if (headlessFragment != null) { - fragManager.beginTransaction().remove(headlessFragment).commitAllowingStateLoss() - } - - val fragment = KeyguardLaunchFragment() - fragment.init(purpose, callback) - fragManager.beginTransaction().add(fragment, TAG_KEYGUARD_FRAGMENT).commit() - } - - - } -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtection.kt b/signer/src/main/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtection.kt deleted file mode 100644 index 815c284c..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/encryption/SimpleAsymmetricProtection.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.uport.sdk.signer.encryption - -import android.content.Context -import com.uport.sdk.signer.DecryptionCallback -import com.uport.sdk.signer.EncryptionCallback -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.generateWrappingKey - -class SimpleAsymmetricProtection : KeyProtection() { - - override - val alias = "__simple_asymmetric_key_alias__" - - override - fun genKey(context: Context) { - - generateWrappingKey(context, alias) - - } - - override - fun encrypt(context: Context, purpose: String, blob: ByteArray, callback: EncryptionCallback) { - try { - val ciphertext = encryptRaw(blob, alias) - callback(null, ciphertext) - } catch (ex: Exception) { - callback(ex, "") - } - } - - - override - fun decrypt(context: Context, purpose: String, ciphertext: String, callback: DecryptionCallback) { - try { - val decryptedBytes = decryptRaw(ciphertext, alias) - callback(null, decryptedBytes) - } catch (ex: Exception) { - callback(ex, ByteArray(0)) - } - } - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/storage/CryptoUtil.kt b/signer/src/main/java/com/uport/sdk/signer/storage/CryptoUtil.kt deleted file mode 100644 index 5886eec0..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/storage/CryptoUtil.kt +++ /dev/null @@ -1,126 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.uport.sdk.signer.storage - -import android.annotation.SuppressLint -import android.annotation.TargetApi -import android.content.Context -import android.os.Build -import android.security.keystore.KeyGenParameterSpec -import android.security.keystore.KeyProperties -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.ANDROID_KEYSTORE_PROVIDER -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.generateWrappingKey -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.getKeyStore -import com.uport.sdk.signer.encryption.AndroidKeyStoreHelper.getWrappingCipher -import com.uport.sdk.signer.hasMarshmallow -import com.uport.sdk.signer.packCiphertext -import com.uport.sdk.signer.unpackCiphertext -import java.security.SecureRandom -import javax.crypto.Cipher -import javax.crypto.Cipher.* -import javax.crypto.KeyGenerator -import javax.crypto.SecretKey -import javax.crypto.spec.IvParameterSpec - - -class CryptoUtil(context: Context, private val alias: String = DEFAULT_ALIAS) { - - private val appContext = context.applicationContext - - //used for symmetric encryption on API 23+ - @TargetApi(Build.VERSION_CODES.M) - private fun genEncryptionKey(): SecretKey { - val keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES, ANDROID_KEYSTORE_PROVIDER) - val purpose = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT - val builder = KeyGenParameterSpec.Builder(alias, purpose) - - builder.setBlockModes(BLOCK_MODE) - .setKeySize(AES_KEY_SIZE) - .setEncryptionPaddings(BLOCK_PADDING) - - keyGenerator.init(builder.build()) - - return keyGenerator.generateKey() - } - - private fun genOneTimeKey(): SecretKey { - val gen = KeyGenerator.getInstance(ALGORITHM_AES) - gen.init(AES_KEY_SIZE, SecureRandom()) - - return gen.generateKey() - } - - fun encrypt(blob: ByteArray): String { - val keyStore = getKeyStore() - - if (hasMarshmallow()) { - val cipher = Cipher.getInstance(AES_TRANSFORMATION) - - val secretKey = keyStore.getKey(alias, null) ?: genEncryptionKey() - cipher.init(Cipher.ENCRYPT_MODE, secretKey) - //FIXME: On some devices (like emulator with API 24 & 26) this throws IllegalBlockSizeException for large blobs (ex 4096 bytes) - val encryptedBytes = cipher.doFinal(blob) - - return packCiphertext(cipher.iv, encryptedBytes) - } else { - val oneTimeKey = genOneTimeKey() - - //ensure public key exists - keyStore.getCertificate(alias)?.publicKey ?: generateWrappingKey(appContext, alias) - - val wrappingCipher = getWrappingCipher(WRAP_MODE, alias) - val wrappedKey = wrappingCipher.wrap(oneTimeKey) - - val encryptingCipher = Cipher.getInstance(AES_TRANSFORMATION) - encryptingCipher.init(ENCRYPT_MODE, oneTimeKey) - val encryptedBlob = encryptingCipher.doFinal(blob) - - return packCiphertext(wrappedKey, encryptingCipher.iv, encryptedBlob) - } - } - - - fun decrypt(ciphertext: String): ByteArray { - - val keyStore = getKeyStore() - - if (hasMarshmallow()) { - - val secretKey = keyStore.getKey(alias, null) ?: genEncryptionKey() - val cipher = Cipher.getInstance(AES_TRANSFORMATION) - - val (iv, encryptedBytes) = unpackCiphertext(ciphertext) - - cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(iv)) - - return cipher.doFinal(encryptedBytes) - } else { - val wrappingCipher = getWrappingCipher(UNWRAP_MODE, alias) - val (wrappedKey, iv, encryptedBytes) = unpackCiphertext(ciphertext) - - val encryptionKey = wrappingCipher.unwrap(wrappedKey, ALGORITHM_AES, SECRET_KEY) - val cipher = Cipher.getInstance(AES_TRANSFORMATION) - cipher.init(Cipher.DECRYPT_MODE, encryptionKey, IvParameterSpec(iv)) - - return cipher.doFinal(encryptedBytes) - } - } - - companion object { - private const val DEFAULT_ALIAS = "simple_protection_key_alias" - - private const val AES_KEY_SIZE = 256 - - @SuppressLint("InlinedApi") - private const val ALGORITHM_AES = KeyProperties.KEY_ALGORITHM_AES - @SuppressLint("InlinedApi") - private const val BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC - @SuppressLint("InlinedApi") - private const val BLOCK_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7 - - private const val AES_TRANSFORMATION = "$ALGORITHM_AES/$BLOCK_MODE/$BLOCK_PADDING" - - } - - -} \ No newline at end of file diff --git a/signer/src/main/java/com/uport/sdk/signer/storage/ProtectedSharedPreferences.kt b/signer/src/main/java/com/uport/sdk/signer/storage/ProtectedSharedPreferences.kt deleted file mode 100644 index 1a79fd20..00000000 --- a/signer/src/main/java/com/uport/sdk/signer/storage/ProtectedSharedPreferences.kt +++ /dev/null @@ -1,310 +0,0 @@ -@file:Suppress("TooManyFunctions") - -package com.uport.sdk.signer.storage - -import android.content.Context -import android.content.SharedPreferences -import android.support.annotation.VisibleForTesting -import android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE - -/** - * Meant to be an encrypted drop in replacement for [SharedPreferences] - * - * This class is NOT thread safe - */ -class ProtectedSharedPreferences( - context: Context, - @VisibleForTesting(otherwise = PACKAGE_PRIVATE) val delegate: SharedPreferences -) : SharedPreferences { - - val crypto = CryptoUtil(context) - - init { - //encrypt all previously nonencrypted data - delegate.all.entries - .filter { (k, v) -> k != null && v != null } - .filter { (k, _) -> !k.matches(Regex("^[sbifle]:.*")) } - .forEach { (k, v) -> - when (v) { - is String -> { - edit().putString(k, v).apply() - delegate.edit().remove(k).apply() - } - is Int -> { - edit().putInt(k, v).apply() - delegate.edit().remove(k).apply() - } - is Boolean -> { - edit().putBoolean(k, v).apply() - delegate.edit().remove(k).apply() - } - is Float -> { - edit().putFloat(k, v).apply() - delegate.edit().remove(k).apply() - } - is Long -> { - edit().putLong(k, v).apply() - delegate.edit().remove(k).apply() - } - is Set<*> -> { - @Suppress("UNCHECKED_CAST") - edit().putStringSet(k, v as MutableSet?).apply() - delegate.edit().remove(k).apply() - } - } - } - } - - override fun contains(key: String?): Boolean { - if (key == null) - return false - - return allKeyPrefixes - .map { "$it:$key" } - .fold(false) { foundIt, queryKey -> - foundIt or (delegate.contains(queryKey) and canDecrypt(queryKey)) - } - } - - private fun canDecrypt(queryKey: String): Boolean { - return try { - if (queryKey.matches("^e:.*".toRegex())) { - val set = delegate.getStringSet(queryKey, mutableSetOf(/*nothing*/)).orEmpty() - set.forEach { crypto.decrypt(it) } - } else { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } - true - } catch (ex: Exception) { - //"removing key: $queryKey because it can't be decrypted" - delegate.edit().remove(queryKey).apply() - false - } - } - - override fun getBoolean(key: String?, default: Boolean): Boolean { - if (key == null) - return default - val queryKey = "b:$key" - if (!delegate.contains(queryKey)) { - return default - } - - val decryptedBytes = try { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - return default - } - - return String(decryptedBytes).toBoolean() - } - - override fun getInt(key: String?, default: Int): Int { - if (key == null) - return default - val queryKey = "i:$key" - if (!delegate.contains(queryKey)) { - return default - } - val decryptedBytes = try { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - return default - } - return String(decryptedBytes).toInt() - } - - override fun getLong(key: String?, default: Long): Long { - if (key == null) - return default - val queryKey = "l:$key" - if (!delegate.contains(queryKey)) { - return default - } - - val decryptedBytes = try { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - return default - } - return String(decryptedBytes).toLong() - } - - override fun getFloat(key: String?, default: Float): Float { - if (key == null) - return default - val queryKey = "f:$key" - if (!delegate.contains(queryKey)) { - return default - } - - val decryptedBytes = try { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - return default - } - return String(decryptedBytes).toFloat() - } - - override fun getString(key: String?, default: String?): String? { - if (key == null) - return default - val queryKey = "s:$key" - if (!delegate.contains(queryKey)) { - return default - } - - val decryptedBytes = try { - crypto.decrypt(delegate.getString(queryKey, "") ?: "") - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - return default - } - return String(decryptedBytes) - } - - override fun getStringSet(key: String?, default: MutableSet?): MutableSet? { - if (key == null) - return default - val queryKey = "e:$key" - if (!delegate.contains(queryKey)) { - return default - } - - val encryptedValues = delegate.getStringSet(queryKey, HashSet()) ?: return default - - return try { - encryptedValues - .map { crypto.decrypt(it) } - .map { String(it) } - .toMutableSet() - } catch (ex: Exception) { - delegate.edit().remove(queryKey).apply() - default - } - } - - override fun edit(): SharedPreferences.Editor { - return EncryptedEditor(delegate.edit(), crypto) - } - - override fun getAll(): MutableMap { - return delegate.all.entries - .filter { (k, v) -> k != null && v != null } - .map { (key, _) -> - - //assumes all key prefixes are length 2 - val queryKey = key.substring(2) - - val value: Any? = when { - Regex("^s:.*").matches(key) -> getString(queryKey, null) - Regex("^b:.*").matches(key) -> getBoolean(queryKey, false) - Regex("^i:.*").matches(key) -> getInt(queryKey, 0) - Regex("^f:.*").matches(key) -> getFloat(queryKey, 0f) - Regex("^l:.*").matches(key) -> getLong(queryKey, 0L) - Regex("^e:.*").matches(key) -> getStringSet(queryKey, null) - else -> { - null - } - } - - //this assume all key prefixes are length 2 ("s:") - Pair(queryKey, value) - } - .toMap() - .toMutableMap() - } - - override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { - //todo: listener will be called with wrong keys; they need to be decrypted before calling - delegate.registerOnSharedPreferenceChangeListener(listener) - } - - override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { - //todo: listener will be called with wrong keys; they need to be decrypted before calling - delegate.unregisterOnSharedPreferenceChangeListener(listener) - } - - class EncryptedEditor(private var delegate: SharedPreferences.Editor, val crypto: CryptoUtil) : SharedPreferences.Editor { - - override fun clear(): SharedPreferences.Editor { - delegate.clear() - return this - } - - private fun putPrimitive(key: String?, value: Any?, typePrefix: String = "s"): SharedPreferences.Editor { - if (key == null) - return this - - val encryptedValue = crypto.encrypt(value.toString().toByteArray()) - delegate.putString("$typePrefix:$key", encryptedValue) - return this - } - - override fun putLong(key: String?, value: Long): SharedPreferences.Editor { - return putPrimitive(key, value, "l") - } - - override fun putInt(key: String?, value: Int): SharedPreferences.Editor { - return putPrimitive(key, value, "i") - } - - override fun remove(key: String?): SharedPreferences.Editor { - - allKeyPrefixes - .map { "$it:$key" } - .forEach { - delegate.remove(it) - } - - return this - } - - override fun putBoolean(key: String?, value: Boolean): SharedPreferences.Editor { - return putPrimitive(key, value, "b") - } - - override fun putStringSet(key: String?, valueSet: MutableSet?): SharedPreferences.Editor { - if (key == null || valueSet == null) - return this - val queryKey = "e:$key" - - val encryptedValues = valueSet - .map { crypto.encrypt(it.toByteArray()) } - .toMutableSet() - - return delegate.putStringSet(queryKey, encryptedValues) - } - - override fun commit(): Boolean { - return delegate.commit() - } - - override fun putFloat(key: String?, value: Float): SharedPreferences.Editor { - return putPrimitive(key, value, "f") - } - - override fun apply() { - delegate.apply() - } - - override fun putString(key: String?, value: String?): SharedPreferences.Editor { - return putPrimitive(key, value, "s") - } - - } - - companion object { - - //these prefixes, followed by a `:` signal the presence of an encrypted value. - //there is a lot of space for collision with such short prefixes - //TODO: use longer prefixes - internal val allKeyPrefixes = listOf("b", "s", "i", "l", "f", "e") - - } - -} diff --git a/signer/src/main/res/drawable/uport_ic_fingerprint_done.xml b/signer/src/main/res/drawable/uport_ic_fingerprint_done.xml deleted file mode 100644 index 92360da0..00000000 --- a/signer/src/main/res/drawable/uport_ic_fingerprint_done.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/signer/src/main/res/drawable/uport_ic_fingerprint_error.xml b/signer/src/main/res/drawable/uport_ic_fingerprint_error.xml deleted file mode 100644 index 52ea0452..00000000 --- a/signer/src/main/res/drawable/uport_ic_fingerprint_error.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/signer/src/main/res/drawable/uport_ic_fingerprint_idle.xml b/signer/src/main/res/drawable/uport_ic_fingerprint_idle.xml deleted file mode 100644 index 0c40a1d3..00000000 --- a/signer/src/main/res/drawable/uport_ic_fingerprint_idle.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/signer/src/main/res/layout/fragment_fingerprint.xml b/signer/src/main/res/layout/fragment_fingerprint.xml deleted file mode 100644 index 91e8c1c7..00000000 --- a/signer/src/main/res/layout/fragment_fingerprint.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - -