Merge pull request #466 from believethehype/main

added NIP98 Support, Added nostrcheck.me Image hoster
This commit is contained in:
Vitor Pamplona
2023-06-23 12:26:51 -04:00
committed by GitHub
6 changed files with 89 additions and 14 deletions
@@ -23,6 +23,7 @@ import com.vitorpamplona.amethyst.service.NostrThreadDataSource
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
import com.vitorpamplona.amethyst.service.NostrVideoDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource
import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.amethyst.ui.actions.ImageUploader
object ServiceManager { object ServiceManager {
private var account: Account? = null private var account: Account? = null
@@ -66,6 +67,7 @@ object ServiceManager {
NostrHomeDataSource.account = myAccount NostrHomeDataSource.account = myAccount
NostrChatroomListDataSource.account = myAccount NostrChatroomListDataSource.account = myAccount
NostrVideoDataSource.account = myAccount NostrVideoDataSource.account = myAccount
ImageUploader.account = myAccount
// Notification Elements // Notification Elements
NostrHomeDataSource.start() NostrHomeDataSource.start()
@@ -7,19 +7,24 @@ import android.webkit.MimeTypeMap
import androidx.core.net.toFile import androidx.core.net.toFile
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.BuildConfig
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.toHexKey
import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.HttpClient
import com.vitorpamplona.amethyst.service.model.Event
import okhttp3.* import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okio.BufferedSink import okio.BufferedSink
import okio.IOException
import okio.source import okio.source
import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.security.MessageDigest
import java.util.Base64
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
fun randomChars() = List(16) { charPool.random() }.joinToString("") fun randomChars() = List(16) { charPool.random() }.joinToString("")
object ImageUploader { object ImageUploader {
lateinit var account: Account
fun uploadImage( fun uploadImage(
uri: Uri, uri: Uri,
@@ -33,12 +38,11 @@ object ImageUploader {
val myContentType = contentType ?: contentResolver.getType(uri) val myContentType = contentType ?: contentResolver.getType(uri)
val imageInputStream = contentResolver.openInputStream(uri) val imageInputStream = contentResolver.openInputStream(uri)
val length = size val length = size ?: contentResolver.query(uri, null, null, null, null)?.use {
?: contentResolver.query(uri, null, null, null, null)?.use { it.moveToFirst()
it.moveToFirst() val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE)
val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE) it.getLong(sizeIndex)
it.getLong(sizeIndex) } ?: kotlin.runCatching {
} ?: kotlin.runCatching {
uri.toFile().length() uri.toFile().length()
}.getOrNull() ?: 0 }.getOrNull() ?: 0
@@ -58,6 +62,9 @@ object ImageUploader {
ServersAvailable.NOSTRFILES_DEV, ServersAvailable.NOSTRFILES_DEV_NIP_94 -> { ServersAvailable.NOSTRFILES_DEV, ServersAvailable.NOSTRFILES_DEV_NIP_94 -> {
NostrFilesDevServer() NostrFilesDevServer()
} }
ServersAvailable.NOSTRCHECK_ME, ServersAvailable.NOSTRCHECK_ME_NIP_94 -> {
NostrCheckMeServer()
}
else -> { else -> {
NostrBuildServer() NostrBuildServer()
} }
@@ -99,7 +106,7 @@ object ImageUploader {
) )
.build() .build()
server.clientID()?.let { server.clientID(requestBody.toString())?.let {
requestBuilder.addHeader("Authorization", it) requestBuilder.addHeader("Authorization", it)
} }
@@ -133,6 +140,18 @@ object ImageUploader {
} }
}) })
} }
fun NIP98Header(url: String, method: String, body: String): String {
var hash = ""
if (body != "") {
val sha256 = MessageDigest.getInstance("SHA-256")
hash = sha256.digest(body.toByteArray()).toHexKey()
}
var tags = listOf(listOf("u", url), listOf("method", method), listOf("payload", hash))
var noteJson = (Event.create(account.loggedIn.privKey!!, 27235, tags, "")).toJson()
val encodedNIP98Event: String = Base64.getEncoder().encodeToString(noteJson.toByteArray())
return "Nostr " + encodedNIP98Event
}
} }
abstract class FileServer { abstract class FileServer {
@@ -140,7 +159,7 @@ abstract class FileServer {
abstract fun parseUrlFromSuccess(body: String): String? abstract fun parseUrlFromSuccess(body: String): String?
abstract fun inputParameterName(contentType: String?): String abstract fun inputParameterName(contentType: String?): String
open fun clientID(): String? = null open fun clientID(info: String): String? = null
} }
class NostrImgServer : FileServer() { class NostrImgServer : FileServer() {
@@ -156,7 +175,7 @@ class NostrImgServer : FileServer() {
return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image"
} }
override fun clientID() = null override fun clientID(info: String) = null
} }
class ImgurServer : FileServer() { class ImgurServer : FileServer() {
@@ -175,7 +194,7 @@ class ImgurServer : FileServer() {
return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image"
} }
override fun clientID() = "Client-ID e6aea87296f3f96" override fun clientID(info: String) = "Client-ID e6aea87296f3f96"
} }
class NostrBuildServer : FileServer() { class NostrBuildServer : FileServer() {
@@ -189,7 +208,7 @@ class NostrBuildServer : FileServer() {
return "fileToUpload" return "fileToUpload"
} }
override fun clientID() = null override fun clientID(info: String) = null
} }
class NostrFilesDevServer : FileServer() { class NostrFilesDevServer : FileServer() {
@@ -203,5 +222,43 @@ class NostrFilesDevServer : FileServer() {
return "file" return "file"
} }
override fun clientID() = null override fun clientID(info: String) = null
}
class NostrCheckMeServer : FileServer() {
override fun postUrl(contentType: String?) = "https://nostrcheck.me/api/v1/media"
override fun parseUrlFromSuccess(body: String): String? {
val tree = jacksonObjectMapper().readTree(body)
val url = tree?.get("url")?.asText()
var id = tree?.get("id")?.asText()
var isCompleted = false
val client = OkHttpClient()
var requrl = "https://nostrcheck.me/api/v1/media?id=" + id // + "&apikey=26d075787d261660682fb9d20dbffa538c708b1eda921d0efa2be95fbef4910a"
val request = Request.Builder()
.url(requrl)
.addHeader("Authorization", ImageUploader.NIP98Header(requrl, "GET", ""))
.get()
.build()
while (!isCompleted) {
val response = client.newCall(request).execute()
val body = response.body?.string()
val tree = jacksonObjectMapper().readTree(body)
isCompleted = tree?.get("status")?.asText() == "completed"
try {
Thread.sleep(500)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
return url
}
override fun inputParameterName(contentType: String?): String {
return "mediafile"
}
override fun clientID(body: String) = ImageUploader.NIP98Header("https://nostrcheck.me/api/v1/media", "POST", body)
} }
@@ -50,6 +50,8 @@ open class NewMediaModel : ViewModel() {
selectedServer = ServersAvailable.NOSTR_BUILD_NIP_94 selectedServer = ServersAvailable.NOSTR_BUILD_NIP_94
} else if (selectedServer == ServersAvailable.NOSTRFILES_DEV) { } else if (selectedServer == ServersAvailable.NOSTRFILES_DEV) {
selectedServer = ServersAvailable.NOSTRFILES_DEV_NIP_94 selectedServer = ServersAvailable.NOSTRFILES_DEV_NIP_94
} else if (selectedServer == ServersAvailable.NOSTRCHECK_ME) {
selectedServer = ServersAvailable.NOSTRCHECK_ME_NIP_94
} }
} }
@@ -798,11 +798,13 @@ enum class ServersAvailable {
NOSTR_BUILD, NOSTR_BUILD,
NOSTRIMG, NOSTRIMG,
NOSTRFILES_DEV, NOSTRFILES_DEV,
NOSTRCHECK_ME,
// IMGUR_NIP_94, // IMGUR_NIP_94,
NOSTRIMG_NIP_94, NOSTRIMG_NIP_94,
NOSTR_BUILD_NIP_94, NOSTR_BUILD_NIP_94,
NOSTRFILES_DEV_NIP_94, NOSTRFILES_DEV_NIP_94,
NOSTRCHECK_ME_NIP_94,
NIP95 NIP95
} }
@@ -825,10 +827,12 @@ fun ImageVideoDescription(
Triple(ServersAvailable.NOSTRIMG, stringResource(id = R.string.upload_server_nostrimg), stringResource(id = R.string.upload_server_nostrimg_explainer)), Triple(ServersAvailable.NOSTRIMG, stringResource(id = R.string.upload_server_nostrimg), stringResource(id = R.string.upload_server_nostrimg_explainer)),
Triple(ServersAvailable.NOSTR_BUILD, stringResource(id = R.string.upload_server_nostrbuild), stringResource(id = R.string.upload_server_nostrbuild_explainer)), Triple(ServersAvailable.NOSTR_BUILD, stringResource(id = R.string.upload_server_nostrbuild), stringResource(id = R.string.upload_server_nostrbuild_explainer)),
Triple(ServersAvailable.NOSTRFILES_DEV, stringResource(id = R.string.upload_server_nostrfilesdev), stringResource(id = R.string.upload_server_nostrfilesdev_explainer)), Triple(ServersAvailable.NOSTRFILES_DEV, stringResource(id = R.string.upload_server_nostrfilesdev), stringResource(id = R.string.upload_server_nostrfilesdev_explainer)),
Triple(ServersAvailable.NOSTRCHECK_ME, stringResource(id = R.string.upload_server_nostrcheckme), stringResource(id = R.string.upload_server_nostrcheckme_explainer)),
// Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)), // Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)),
Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)), Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)),
Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)), Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)),
Triple(ServersAvailable.NOSTRFILES_DEV_NIP_94, stringResource(id = R.string.upload_server_nostrfilesdev_nip94), stringResource(id = R.string.upload_server_nostrfilesdev_nip94_explainer)), Triple(ServersAvailable.NOSTRFILES_DEV_NIP_94, stringResource(id = R.string.upload_server_nostrfilesdev_nip94), stringResource(id = R.string.upload_server_nostrfilesdev_nip94_explainer)),
Triple(ServersAvailable.NOSTRCHECK_ME_NIP_94, stringResource(id = R.string.upload_server_nostrcheckme_nip94), stringResource(id = R.string.upload_server_nostrcheckme_nip94_explainer)),
Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer)) Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer))
) )
@@ -383,9 +383,11 @@ fun EditFieldRow(
ServersAvailable.NOSTR_BUILD -> ServersAvailable.NOSTR_BUILD ServersAvailable.NOSTR_BUILD -> ServersAvailable.NOSTR_BUILD
ServersAvailable.NOSTRIMG -> ServersAvailable.NOSTRIMG ServersAvailable.NOSTRIMG -> ServersAvailable.NOSTRIMG
ServersAvailable.NOSTRFILES_DEV -> ServersAvailable.NOSTRFILES_DEV ServersAvailable.NOSTRFILES_DEV -> ServersAvailable.NOSTRFILES_DEV
ServersAvailable.NOSTRCHECK_ME -> ServersAvailable.NOSTRCHECK_ME
ServersAvailable.NOSTR_BUILD_NIP_94 -> ServersAvailable.NOSTR_BUILD ServersAvailable.NOSTR_BUILD_NIP_94 -> ServersAvailable.NOSTR_BUILD
ServersAvailable.NOSTRIMG_NIP_94 -> ServersAvailable.NOSTRIMG ServersAvailable.NOSTRIMG_NIP_94 -> ServersAvailable.NOSTRIMG
ServersAvailable.NOSTRFILES_DEV_NIP_94 -> ServersAvailable.NOSTRFILES_DEV ServersAvailable.NOSTRFILES_DEV_NIP_94 -> ServersAvailable.NOSTRFILES_DEV
ServersAvailable.NOSTRCHECK_ME_NIP_94 -> ServersAvailable.NOSTRCHECK_ME
ServersAvailable.NIP95 -> ServersAvailable.NOSTR_BUILD ServersAvailable.NIP95 -> ServersAvailable.NOSTR_BUILD
} }
} else { } else {
+8
View File
@@ -338,6 +338,9 @@
<string name="upload_server_nostrfilesdev">nostrfiles.dev - trusted</string> <string name="upload_server_nostrfilesdev">nostrfiles.dev - trusted</string>
<string name="upload_server_nostrfilesdev_explainer">Nostrfiles.dev can modify the file</string> <string name="upload_server_nostrfilesdev_explainer">Nostrfiles.dev can modify the file</string>
<string name="upload_server_nostrcheckme">nostrcheck.me - trusted</string>
<string name="upload_server_nostrcheckme_explainer">nostrcheck.me can modify the file</string>
<string name="upload_server_imgur_nip94">Verifiable Imgur (NIP-94)</string> <string name="upload_server_imgur_nip94">Verifiable Imgur (NIP-94)</string>
<string name="upload_server_imgur_nip94_explainer">Checks if Imgur modified the file. New NIP: other clients might not see it</string> <string name="upload_server_imgur_nip94_explainer">Checks if Imgur modified the file. New NIP: other clients might not see it</string>
@@ -351,6 +354,11 @@
<string name="upload_server_nostrfilesdev_nip94">Verifiable Nostrfiles.dev (NIP-94)</string> <string name="upload_server_nostrfilesdev_nip94">Verifiable Nostrfiles.dev (NIP-94)</string>
<string name="upload_server_nostrfilesdev_nip94_explainer">Checks if Nostrfiles.dev modified the file. New NIP: other clients might not see it</string> <string name="upload_server_nostrfilesdev_nip94_explainer">Checks if Nostrfiles.dev modified the file. New NIP: other clients might not see it</string>
<string name="upload_server_nostrcheckme_nip94">Verifiable Nostrcheck.me (NIP-94)</string>
<string name="upload_server_nostrcheckme_nip94_explainer">Checks if Nostrcheck.me modified the file. New NIP: other clients might not see it</string>
<string name="upload_server_relays_nip95">Your relays (NIP-95)</string> <string name="upload_server_relays_nip95">Your relays (NIP-95)</string>
<string name="upload_server_relays_nip95_explainer">Files are hosted by your relays. New NIP: check if they support</string> <string name="upload_server_relays_nip95_explainer">Files are hosted by your relays. New NIP: check if they support</string>