Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unrelease

## [0.6.4] - 2021-07-16
### Changed
- Default Core API endpoint (https://stacks-node-api.stacks.co)

## [0.6.3] - 2021-07-01
### Added
- ability to generate Stacks Addresses
Expand Down
2 changes: 1 addition & 1 deletion blockstack-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {
minSdkVersion 21
targetSdkVersion 30
versionCode 2
versionName "0.6.3"
versionName "0.6.4"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import okhttp3.Request
import okhttp3.Response
import org.blockstack.android.sdk.extensions.toBtcAddress
import org.blockstack.android.sdk.extensions.toHexPublicKey64
import org.blockstack.android.sdk.extensions.toStxAddress
import org.blockstack.android.sdk.model.*
import org.json.JSONArray
import org.json.JSONException
Expand Down Expand Up @@ -99,7 +100,7 @@ class Blockstack(private val callFactory: Call.Factory = OkHttpClient(),
},
"profile_url" to null,
"hubUrl" to "https://hub.blockstack.org",
"blockstackAPIUrl" to "https://core.blockstack.org",
"blockstackAPIUrl" to DEFAULT_CORE_API_ENDPOINT,
"associationToken" to null,
"version" to VERSION
)
Expand Down Expand Up @@ -296,8 +297,21 @@ class Blockstack(private val callFactory: Call.Factory = OkHttpClient(),
val body = response.body!!.string()
val nameInfo = JSONObject(body)
val nameOwningAddress = nameInfo.optString("address")
val addressFromIssuer = DIDs.getAddressFromDID(payload.optString("iss"))
return nameOwningAddress.isNotEmpty() && nameOwningAddress == addressFromIssuer
val addressFromIssuer = DIDs.getAddressFromDID(payload.optString("iss")) ?: ""

//Check if the address is a stx address
return if (nameOwningAddress.startsWith("S")) {
if (nameOwningAddress.isNotEmpty() && nameOwningAddress == addressFromIssuer) {
true
} else {
// Backward Compatibility (Address STX with BTC issuer)
// if the address is not the same, check if the profile belongs to the owner
nameInfo.optString("zonefile").contains(addressFromIssuer)
}
} else {
// legacy
nameOwningAddress.isNotEmpty() && nameOwningAddress == addressFromIssuer
}
} else {
return false
}
Expand Down Expand Up @@ -519,20 +533,16 @@ class Blockstack(private val callFactory: Call.Factory = OkHttpClient(),
}

val issuerPublicKey = payload.getJSONObject("issuer").getString("publicKey")
val uncompressedAddress = issuerPublicKey.toBtcAddress()
val uncompressedBtcAddress = issuerPublicKey.toBtcAddress()
val uncompressedStxAddress = issuerPublicKey.toStxAddress(true)

if (publicKeyOrAddress == issuerPublicKey) {
// pass
} else {
if (publicKeyOrAddress == uncompressedAddress) {
// pass
} else {
throw Error("Token issuer public key does not match the verifying value")
}
} else if (publicKeyOrAddress != uncompressedBtcAddress && publicKeyOrAddress != uncompressedStxAddress) {
throw Error("Token issuer public key does not match the verifying value")
}

return ProfileToken(tokenTripleToJSON(decodedToken))

}

private fun tokenTripleToJSON(decodedToken: Triple<JwtHeader, JSONObject, ByteArray>): JSONObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class BlockstackSession(private val sessionStore: ISessionStore, private val app
*/
suspend fun handlePendingSignIn(authResponse: String): Result<out UserData> = withContext(dispatcher) {
val transitKey = sessionStore.getTransitPrivateKey()
val nameLookupUrl = sessionStore.sessionData.json.optString("core-node", "https://core.blockstack.org")
val nameLookupUrl = sessionStore.sessionData.json.optString("core-node", "stacks-node-api.stacks.co")

val tokenTriple = try {
blockstack.decodeToken(authResponse)
Expand Down Expand Up @@ -92,7 +92,11 @@ class BlockstackSession(private val sessionStore: ISessionStore, private val app
}

suspend fun handleUnencryptedSignIn(authResponse: String): Result<UserData> {
val nameLookupUrl = sessionStore.sessionData.json.optString("core-node", "https://core.blockstack.org")

val nameLookupUrl = sessionStore.sessionData.json.optString(
"core-node",
DEFAULT_CORE_API_ENDPOINT.replace("https://", "")
)

val tokenTriple = blockstack.decodeToken(authResponse)
val tokenPayload = tokenTriple.second
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package org.blockstack.android.sdk

import me.uport.sdk.universaldid.*
import okhttp3.Call
import okhttp3.Request
import org.json.JSONObject
import java.util.*

class DIDs {
Expand All @@ -19,6 +17,8 @@ class DIDs {

if (didType == "btc-addr") {
return did.split(':')[2]
}else if (didType == "stx-addr") {
return did.split(':')[2]
} else {
return null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.blockstack.android.sdk

const val BLOCKSTACK_DEFAULT_GAIA_HUB_URL = "https://hub.blockstack.org"
const val DEFAULT_CORE_API_ENDPOINT = "https://core.blockstack.org"
const val DEFAULT_CORE_API_ENDPOINT = "https://stacks-node-api.stacks.co"
const val DEFAULT_BLOCKSTACK_ID_HOST = "https://app.blockstack.org"
const val LEGACY_BLOCKSTACK_ID_HOST = "https://browser.blockstack.org/auth"
const val VERSION = "1.3.1"
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,32 @@ fun ECKeyPair.toHexPublicKey64(): String {
return this.getCompressedPublicKey().toNoPrefixHexString()
}

fun ECKeyPair.toStxAddress(): String {
fun String.toStxAddress(sPrefix: Boolean = false): String {
val sha256 = hexToByteArray().sha256()
val hash160 = sha256.digestRipemd160()
val extended = "b0${hash160.toNoPrefixHexString()}"
val cs = checksum("16${hash160.toNoPrefixHexString()}")

val prefix = if(sPrefix) "S" else ""
return prefix + (extended + cs).hexToByteArray().encodeCrockford32()
}

fun ECKeyPair.toStxAddress(sPrefix: Boolean = false): String {
val sha256 = toHexPublicKey64().hexToByteArray().sha256()
val hash160 = sha256.digestRipemd160()
val extended = "b0${hash160.toNoPrefixHexString()}"
val cs = checksum("16${hash160.toNoPrefixHexString()}")
return (extended + cs).hexToByteArray().encodeCrockford32()
val prefix = if(sPrefix) "S" else ""
return prefix + (extended + cs).hexToByteArray().encodeCrockford32()
}

fun ECKeyPair.toTestNetStxAddress() : String {
fun ECKeyPair.toTestNetStxAddress(sPrefix: Boolean = false) : String {
val sha256 = toHexPublicKey64().hexToByteArray().sha256()
val hash160 = sha256.digestRipemd160()
val extended = "d0${hash160.toNoPrefixHexString()}"
val cs = checksum("1a${hash160.toNoPrefixHexString()}")
return (extended + cs).hexToByteArray().encodeCrockford32()
val prefix = if(sPrefix) "S" else ""
return prefix + (extended + cs).hexToByteArray().encodeCrockford32()
}

fun String.toBtcAddress(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class AddressesTest {
Assert.assertEquals(PRIVATE_KEY, keys.keyPair.privateKey.key.toHexStringNoPrefix())
Assert.assertEquals(BTC_ADDRESS_MAINNET, keys.keyPair.toBtcAddress())
Assert.assertEquals(STX_ADDRESS_MAINNET, "S${keys.keyPair.toStxAddress()}")
Assert.assertEquals(STX_ADDRESS_MAINNET, keys.keyPair.toStxAddress(true))
}

@Test
Expand All @@ -46,6 +47,7 @@ class AddressesTest {

// Act Assert
Assert.assertEquals(STX_ADDRESS_TESTNET, "S${keys.keyPair.toTestNetStxAddress()}")
Assert.assertEquals(STX_ADDRESS_TESTNET, keys.keyPair.toTestNetStxAddress(true))
}


Expand Down
5 changes: 2 additions & 3 deletions example/src/main/java/org/blockstack/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ class MainActivity : AppCompatActivity() {
}

getStringFileFromUserButton.setOnClickListener {

val zoneFileLookupUrl = URL("https://core.blockstack.org/v1/names")
val zoneFileLookupUrl = URL("https://stacks-node-api.stacks.co/v1/names")
fileFromUserContentsTextView.text = "Downloading file from other user..."
lifecycleScope.launch {
val profile = blockstack.lookupProfile(username, zoneFileLookupURL = zoneFileLookupUrl)
Expand Down Expand Up @@ -225,7 +224,7 @@ class MainActivity : AppCompatActivity() {

getUserAppFileUrlButton.setOnClickListener { _ ->
getUserAppFileUrlText.text = "Getting url ..."
val zoneFileLookupUrl = "https://core.blockstack.org/v1/names"
val zoneFileLookupUrl = DEFAULT_CORE_API_ENDPOINT + "v1/names"
lifecycleScope.launch {
val it = blockstack.getUserAppFileUrl(textFileName, username, "https://flamboyant-darwin-d11c17.netlify.app", zoneFileLookupUrl)
withContext(Dispatchers.Main) {
Expand Down