Allows login with NIP-05 address

This commit is contained in:
Vitor Pamplona
2024-06-15 12:33:43 -04:00
parent ae0ae413e6
commit 80d506be37
2 changed files with 36 additions and 48 deletions

View File

@@ -25,12 +25,9 @@ import com.vitorpamplona.amethyst.BuildConfig
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Request
import okhttp3.Response
class Nip05NostrAddressVerifier() {
class Nip05NostrAddressVerifier {
fun assembleUrl(nip05address: String): String? {
val parts = nip05address.trim().split("@")
@@ -46,7 +43,7 @@ class Nip05NostrAddressVerifier() {
suspend fun fetchNip05Json(
nip05: String,
onSuccess: (String) -> Unit,
onSuccess: suspend (String) -> Unit,
onError: (String) -> Unit,
) = withContext(Dispatchers.IO) {
checkNotInMainThread()
@@ -60,52 +57,39 @@ class Nip05NostrAddressVerifier() {
try {
val request =
Request.Builder()
Request
.Builder()
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
.url(url)
.build()
// Fetchers MUST ignore any HTTP redirects given by the /.well-known/nostr.json endpoint.
HttpClientManager.getHttpClient().newBuilder().followRedirects(false).build()
HttpClientManager
.getHttpClient()
.newBuilder()
.followRedirects(false)
.build()
.newCall(request)
.enqueue(
object : Callback {
override fun onResponse(
call: Call,
response: Response,
) {
checkNotInMainThread()
.execute()
.use {
checkNotInMainThread()
response.use {
if (it.isSuccessful) {
onSuccess(it.body.string())
} else {
onError(
"Could not resolve $nip05. Error: ${it.code}. Check if the server is up and if the address $nip05 is correct",
)
}
}
}
override fun onFailure(
call: Call,
e: java.io.IOException,
) {
onError(
"Could not resolve $url. Check if the server is up and if the address $nip05 is correct",
)
e.printStackTrace()
}
},
)
if (it.isSuccessful) {
onSuccess(it.body.string())
} else {
onError(
"Could not resolve $nip05. Error: ${it.code}. Check if the server is up and if the address $nip05 is correct",
)
}
}
} catch (e: Exception) {
if (e is CancellationException) throw e
onError("Could not resolve '$url': ${e.message}")
onError("Could not resolve NIP-05 $nip05 as URL $url: ${e.message}")
}
}
suspend fun verifyNip05(
nip05: String,
onSuccess: (String) -> Unit,
onSuccess: suspend (String) -> Unit,
onError: (String) -> Unit,
) {
// check fails on tests

View File

@@ -29,6 +29,7 @@ import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.HttpClientManager
import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier
import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.quartz.crypto.CryptoUtils
import com.vitorpamplona.quartz.crypto.KeyPair
@@ -57,7 +58,7 @@ import java.util.regex.Pattern
val EMAIL_PATTERN = Pattern.compile(".+@.+\\.[a-z]+")
@Stable
class AccountStateViewModel() : ViewModel() {
class AccountStateViewModel : ViewModel() {
var serviceManager: ServiceManager? = null
private val _accountContent = MutableStateFlow<AccountState>(AccountState.Loading)
@@ -144,15 +145,6 @@ class AccountStateViewModel() : ViewModel() {
proxyPort = proxyPort,
signer = NostrSignerInternal(keyPair),
)
} else if (EMAIL_PATTERN.matcher(key).matches()) {
val keyPair = KeyPair()
// TODO: Evaluate NIP-5
Account(
keyPair,
proxy = proxy,
proxyPort = proxyPort,
signer = NostrSignerInternal(keyPair),
)
} else {
val keyPair = KeyPair(Hex.decode(key))
Account(
@@ -243,6 +235,18 @@ class AccountStateViewModel() : ViewModel() {
onError(null)
}
}
} else if (EMAIL_PATTERN.matcher(key).matches()) {
Nip05NostrAddressVerifier().verifyNip05(
key,
onSuccess = { publicKey ->
loginSync(Hex.decode(publicKey).toNpub(), useProxy, proxyPort, loginWithExternalSigner, packageName) {
onError(null)
}
},
onError = {
onError(it)
},
)
} else {
loginSync(key, useProxy, proxyPort, loginWithExternalSigner, packageName) {
onError(null)