mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
wip: implement ons name
This commit is contained in:
parent
ad51bbb847
commit
ae23266058
@ -430,7 +430,7 @@ object OnionRequestAPI {
|
|||||||
/**
|
/**
|
||||||
* Sends an onion request to `snode`. Builds new paths as needed.
|
* Sends an onion request to `snode`. Builds new paths as needed.
|
||||||
*/
|
*/
|
||||||
internal fun sendOnionRequest(method: Snode.Method, parameters: Map<*, *>, snode: Snode, publicKey: String): Promise<Map<*, *>, Exception> {
|
internal fun sendOnionRequest(method: Snode.Method, parameters: Map<*, *>, snode: Snode, publicKey: String? = null): Promise<Map<*, *>, Exception> {
|
||||||
val payload = mapOf( "method" to method.rawValue, "params" to parameters )
|
val payload = mapOf( "method" to method.rawValue, "params" to parameters )
|
||||||
return sendOnionRequest(Destination.Snode(snode), payload).recover { exception ->
|
return sendOnionRequest(Destination.Snode(snode), payload).recover { exception ->
|
||||||
val httpRequestFailedException = exception as? HTTP.HTTPRequestFailedException
|
val httpRequestFailedException = exception as? HTTP.HTTPRequestFailedException
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
package org.session.libsession.snode
|
package org.session.libsession.snode
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import com.goterl.lazysodium.LazySodiumAndroid
|
||||||
|
import com.goterl.lazysodium.SodiumAndroid
|
||||||
|
import com.goterl.lazysodium.interfaces.PwHash
|
||||||
|
import com.goterl.lazysodium.interfaces.SecretBox
|
||||||
import nl.komponents.kovenant.*
|
import nl.komponents.kovenant.*
|
||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
import nl.komponents.kovenant.functional.map
|
import nl.komponents.kovenant.functional.map
|
||||||
@ -17,10 +21,14 @@ import org.session.libsignal.utilities.prettifiedDescription
|
|||||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
||||||
import org.session.libsignal.utilities.retryIfNeeded
|
import org.session.libsignal.utilities.retryIfNeeded
|
||||||
import org.session.libsignal.utilities.*
|
import org.session.libsignal.utilities.*
|
||||||
|
import org.session.libsignal.utilities.Base64
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object SnodeAPI {
|
object SnodeAPI {
|
||||||
|
private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }
|
||||||
|
|
||||||
private val database: LokiAPIDatabaseProtocol
|
private val database: LokiAPIDatabaseProtocol
|
||||||
get() = SnodeModule.shared.storage
|
get() = SnodeModule.shared.storage
|
||||||
private val broadcaster: Broadcaster
|
private val broadcaster: Broadcaster
|
||||||
@ -54,10 +62,14 @@ object SnodeAPI {
|
|||||||
internal sealed class Error(val description: String) : Exception(description) {
|
internal sealed class Error(val description: String) : Exception(description) {
|
||||||
object Generic : Error("An error occurred.")
|
object Generic : Error("An error occurred.")
|
||||||
object ClockOutOfSync : Error("Your clock is out of sync with the Service Node network.")
|
object ClockOutOfSync : Error("Your clock is out of sync with the Service Node network.")
|
||||||
|
// ONS
|
||||||
|
object DecryptionFailed : Error("Couldn't decrypt ONS name.")
|
||||||
|
object HashingFailed : Error("Couldn't compute ONS name hash.")
|
||||||
|
object ValidationFailed : Error("ONS name validation failed.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal API
|
// Internal API
|
||||||
internal fun invoke(method: Snode.Method, snode: Snode, publicKey: String, parameters: Map<String, String>): RawResponsePromise {
|
internal fun invoke(method: Snode.Method, snode: Snode, publicKey: String? = null, parameters: Map<String, Any>): RawResponsePromise {
|
||||||
val url = "${snode.address}:${snode.port}/storage_rpc/v1"
|
val url = "${snode.address}:${snode.port}/storage_rpc/v1"
|
||||||
if (useOnionRequests) {
|
if (useOnionRequests) {
|
||||||
return OnionRequestAPI.sendOnionRequest(method, parameters, snode, publicKey)
|
return OnionRequestAPI.sendOnionRequest(method, parameters, snode, publicKey)
|
||||||
@ -153,6 +165,50 @@ object SnodeAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
|
fun getSessionIDFor(onsName: String): Promise<String, Exception> {
|
||||||
|
val validationCount = 3
|
||||||
|
val sessionIDByteCount = 33
|
||||||
|
// Hash the ONS name using BLAKE2b
|
||||||
|
val name = onsName.toLowerCase(Locale.ENGLISH)
|
||||||
|
val nameHash = sodium.cryptoGenericHash(name)
|
||||||
|
val base64EncodedNameHash = nameHash
|
||||||
|
// Ask 3 different snodes for the Session ID associated with the given name hash
|
||||||
|
val parameters = mapOf(
|
||||||
|
"endpoint" to "ons_resolve",
|
||||||
|
"params" to mapOf( "type" to 0, "name_hash" to base64EncodedNameHash )
|
||||||
|
)
|
||||||
|
val promises = (0..validationCount).map {
|
||||||
|
getRandomSnode().bind { snode ->
|
||||||
|
invoke(Snode.Method.OxenDaemonRPCCall, snode, null, parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val deferred = deferred<String, Exception>()
|
||||||
|
val promise = deferred.promise
|
||||||
|
all(promises).success { results ->
|
||||||
|
val sessionIDs = mutableListOf<String>()
|
||||||
|
for (json in results) {
|
||||||
|
val intermediate = json["result"] as? Map<*, *>
|
||||||
|
val hexEncodedCiphertext = intermediate?.get("encrypted_value") as? String
|
||||||
|
if (hexEncodedCiphertext != null) {
|
||||||
|
val ciphertext = Hex.fromStringCondensed(hexEncodedCiphertext)
|
||||||
|
val isArgon2Based = (intermediate["nonce"] == null)
|
||||||
|
if (isArgon2Based) {
|
||||||
|
// Handle old Argon2-based encryption used before HF16
|
||||||
|
val salt = ByteArray(PwHash.SALTBYTES)
|
||||||
|
val key = sodium.cryptoPwHash(name, SecretBox.KEYBYTES, salt, PwHash.OPSLIMIT_MODERATE, PwHash.MEMLIMIT_MODERATE, PwHash.Alg.PWHASH_ALG_ARGON2ID13)
|
||||||
|
val nonce = ByteArray(SecretBox.NONCEBYTES)
|
||||||
|
val sessionID = sodium.cryptoSecretBoxOpenEasy(ciphertext, nonce, key)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deferred.reject(Error.Generic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
|
||||||
fun getTargetSnodes(publicKey: String): Promise<List<Snode>, Exception> {
|
fun getTargetSnodes(publicKey: String): Promise<List<Snode>, Exception> {
|
||||||
// SecureRandom() should be cryptographically secure
|
// SecureRandom() should be cryptographically secure
|
||||||
return getSwarm(publicKey).map { it.shuffled(SecureRandom()).take(targetSwarmSnodeCount) }
|
return getSwarm(publicKey).map { it.shuffled(SecureRandom()).take(targetSwarmSnodeCount) }
|
||||||
|
@ -6,7 +6,8 @@ class Snode(val address: String, val port: Int, val publicKeySet: KeySet?) {
|
|||||||
public enum class Method(val rawValue: String) {
|
public enum class Method(val rawValue: String) {
|
||||||
GetSwarm("get_snodes_for_pubkey"),
|
GetSwarm("get_snodes_for_pubkey"),
|
||||||
GetMessages("retrieve"),
|
GetMessages("retrieve"),
|
||||||
SendMessage("store")
|
SendMessage("store"),
|
||||||
|
OxenDaemonRPCCall("oxend_request")
|
||||||
}
|
}
|
||||||
|
|
||||||
data class KeySet(val ed25519Key: String, val x25519Key: String)
|
data class KeySet(val ed25519Key: String, val x25519Key: String)
|
||||||
|
Loading…
Reference in New Issue
Block a user