support for sending and receiving nip 44 dms
This commit is contained in:
@@ -16,6 +16,7 @@ import com.vitorpamplona.amethyst.service.relays.Constants
|
|||||||
import com.vitorpamplona.amethyst.service.relays.FeedType
|
import com.vitorpamplona.amethyst.service.relays.FeedType
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
import com.vitorpamplona.amethyst.service.relays.RelayPool
|
import com.vitorpamplona.amethyst.service.relays.RelayPool
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.SignerType
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||||
import com.vitorpamplona.amethyst.ui.note.combineWith
|
import com.vitorpamplona.amethyst.ui.note.combineWith
|
||||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||||
@@ -114,7 +115,8 @@ class Account(
|
|||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
AmberUtils.decrypt(
|
AmberUtils.decrypt(
|
||||||
content,
|
content,
|
||||||
keyPair.pubKey.toHexKey()
|
keyPair.pubKey.toHexKey(),
|
||||||
|
blockList?.id() ?: ""
|
||||||
)
|
)
|
||||||
blockList?.decryptedContent = AmberUtils.content
|
blockList?.decryptedContent = AmberUtils.content
|
||||||
live.invalidateData()
|
live.invalidateData()
|
||||||
@@ -282,7 +284,7 @@ class Account(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.event is ChatMessageEvent && !loginWithAmber) {
|
if (note.event is ChatMessageEvent) {
|
||||||
val event = note.event as ChatMessageEvent
|
val event = note.event as ChatMessageEvent
|
||||||
val users = event.recipientsPubKey().plus(event.pubKey).toSet().toList()
|
val users = event.recipientsPubKey().plus(event.pubKey).toSet().toList()
|
||||||
|
|
||||||
@@ -290,21 +292,91 @@ class Account(
|
|||||||
val emojiUrl = EmojiUrl.decode(reaction)
|
val emojiUrl = EmojiUrl.decode(reaction)
|
||||||
if (emojiUrl != null) {
|
if (emojiUrl != null) {
|
||||||
note.event?.let {
|
note.event?.let {
|
||||||
|
if (loginWithAmber) {
|
||||||
|
val senderPublicKey = keyPair.pubKey.toHexKey()
|
||||||
|
|
||||||
|
var senderReaction = ReactionEvent.create(
|
||||||
|
emojiUrl,
|
||||||
|
it,
|
||||||
|
keyPair
|
||||||
|
)
|
||||||
|
|
||||||
|
AmberUtils.openAmber(senderReaction)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
senderReaction = ReactionEvent.create(senderReaction, AmberUtils.content)
|
||||||
|
|
||||||
|
val giftWraps = users.plus(senderPublicKey).map {
|
||||||
|
val gossip = Gossip.create(senderReaction)
|
||||||
|
val content = Gossip.toJson(gossip)
|
||||||
|
AmberUtils.encrypt(content, it, SignerType.NIP44_ENCRYPT)
|
||||||
|
|
||||||
|
var sealedEvent = SealedGossipEvent.create(
|
||||||
|
encryptedContent = AmberUtils.content,
|
||||||
|
pubKey = senderPublicKey
|
||||||
|
)
|
||||||
|
AmberUtils.openAmber(sealedEvent)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
sealedEvent = SealedGossipEvent.create(sealedEvent, AmberUtils.content)
|
||||||
|
|
||||||
|
GiftWrapEvent.create(
|
||||||
|
event = sealedEvent,
|
||||||
|
recipientPubKey = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcastPrivately(giftWraps)
|
||||||
|
} else {
|
||||||
val giftWraps = NIP24Factory().createReactionWithinGroup(
|
val giftWraps = NIP24Factory().createReactionWithinGroup(
|
||||||
emojiUrl = emojiUrl,
|
emojiUrl = emojiUrl,
|
||||||
originalNote = it,
|
originalNote = it,
|
||||||
to = users,
|
to = users,
|
||||||
from = keyPair
|
from = keyPair
|
||||||
)
|
)
|
||||||
|
|
||||||
broadcastPrivately(giftWraps)
|
broadcastPrivately(giftWraps)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
note.event?.let {
|
note.event?.let {
|
||||||
|
if (loginWithAmber) {
|
||||||
|
val senderPublicKey = keyPair.pubKey.toHexKey()
|
||||||
|
|
||||||
|
var senderReaction = ReactionEvent.create(
|
||||||
|
reaction,
|
||||||
|
it,
|
||||||
|
keyPair
|
||||||
|
)
|
||||||
|
|
||||||
|
AmberUtils.openAmber(senderReaction)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
senderReaction = ReactionEvent.create(senderReaction, AmberUtils.content)
|
||||||
|
|
||||||
|
val newUsers = users.plus(senderPublicKey)
|
||||||
|
newUsers.forEach {
|
||||||
|
val gossip = Gossip.create(senderReaction)
|
||||||
|
val content = Gossip.toJson(gossip)
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.encrypt(content, it, SignerType.NIP44_ENCRYPT)
|
||||||
|
|
||||||
|
var sealedEvent = SealedGossipEvent.create(
|
||||||
|
encryptedContent = AmberUtils.content,
|
||||||
|
pubKey = senderPublicKey
|
||||||
|
)
|
||||||
|
AmberUtils.openAmber(sealedEvent)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
sealedEvent = SealedGossipEvent.create(sealedEvent, AmberUtils.content)
|
||||||
|
|
||||||
|
val giftWraps = GiftWrapEvent.create(
|
||||||
|
event = sealedEvent,
|
||||||
|
recipientPubKey = it
|
||||||
|
)
|
||||||
|
|
||||||
|
broadcastPrivately(listOf(giftWraps))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val giftWraps = NIP24Factory().createReactionWithinGroup(
|
val giftWraps = NIP24Factory().createReactionWithinGroup(
|
||||||
content = reaction,
|
content = reaction,
|
||||||
originalNote = it,
|
originalNote = it,
|
||||||
@@ -314,6 +386,7 @@ class Account(
|
|||||||
|
|
||||||
broadcastPrivately(giftWraps)
|
broadcastPrivately(giftWraps)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if (reaction.startsWith(":")) {
|
if (reaction.startsWith(":")) {
|
||||||
@@ -1373,13 +1446,52 @@ class Account(
|
|||||||
wantsToMarkAsSensitive: Boolean,
|
wantsToMarkAsSensitive: Boolean,
|
||||||
zapRaiserAmount: Long? = null,
|
zapRaiserAmount: Long? = null,
|
||||||
geohash: String? = null
|
geohash: String? = null
|
||||||
): List<GiftWrapEvent>? {
|
) {
|
||||||
// TODO: add support for amber
|
if (!isWriteable() && !loginWithAmber) return
|
||||||
if (!isWriteable() && !loginWithAmber) return null
|
|
||||||
|
|
||||||
val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null }
|
val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null }
|
||||||
val mentionsHex = mentions?.map { it.pubkeyHex }
|
val mentionsHex = mentions?.map { it.pubkeyHex }
|
||||||
|
|
||||||
|
if (loginWithAmber) {
|
||||||
|
var chatMessageEvent = ChatMessageEvent.create(
|
||||||
|
msg = message,
|
||||||
|
to = toUsers,
|
||||||
|
keyPair = keyPair,
|
||||||
|
subject = subject,
|
||||||
|
replyTos = repliesToHex,
|
||||||
|
mentions = mentionsHex,
|
||||||
|
zapReceiver = zapReceiver,
|
||||||
|
markAsSensitive = wantsToMarkAsSensitive,
|
||||||
|
zapRaiserAmount = zapRaiserAmount,
|
||||||
|
geohash = geohash
|
||||||
|
)
|
||||||
|
|
||||||
|
AmberUtils.openAmber(chatMessageEvent)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
chatMessageEvent = ChatMessageEvent.create(chatMessageEvent, AmberUtils.content)
|
||||||
|
val senderPublicKey = keyPair.pubKey.toHexKey()
|
||||||
|
toUsers.plus(senderPublicKey).toSet().forEach {
|
||||||
|
val gossip = Gossip.create(chatMessageEvent)
|
||||||
|
val content = Gossip.toJson(gossip)
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.encrypt(content, it, SignerType.NIP44_ENCRYPT)
|
||||||
|
if (AmberUtils.content.isNotBlank()) {
|
||||||
|
var sealedEvent = SealedGossipEvent.create(
|
||||||
|
encryptedContent = AmberUtils.content,
|
||||||
|
pubKey = senderPublicKey
|
||||||
|
)
|
||||||
|
AmberUtils.openAmber(sealedEvent)
|
||||||
|
if (AmberUtils.content.isBlank()) return
|
||||||
|
sealedEvent = SealedGossipEvent.create(sealedEvent, AmberUtils.content)
|
||||||
|
|
||||||
|
val giftWraps = GiftWrapEvent.create(
|
||||||
|
event = sealedEvent,
|
||||||
|
recipientPubKey = it
|
||||||
|
)
|
||||||
|
broadcastPrivately(listOf(giftWraps))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val signedEvents = NIP24Factory().createMsgNIP24(
|
val signedEvents = NIP24Factory().createMsgNIP24(
|
||||||
msg = message,
|
msg = message,
|
||||||
to = toUsers,
|
to = toUsers,
|
||||||
@@ -1390,15 +1502,11 @@ class Account(
|
|||||||
markAsSensitive = wantsToMarkAsSensitive,
|
markAsSensitive = wantsToMarkAsSensitive,
|
||||||
zapRaiserAmount = zapRaiserAmount,
|
zapRaiserAmount = zapRaiserAmount,
|
||||||
geohash = geohash,
|
geohash = geohash,
|
||||||
from = keyPair.privKey!!
|
keyPair = keyPair
|
||||||
)
|
)
|
||||||
|
|
||||||
if (loginWithAmber) {
|
|
||||||
return signedEvents
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastPrivately(signedEvents)
|
broadcastPrivately(signedEvents)
|
||||||
return null
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun broadcastPrivately(signedEvents: List<GiftWrapEvent>) {
|
fun broadcastPrivately(signedEvents: List<GiftWrapEvent>) {
|
||||||
@@ -1407,6 +1515,25 @@ class Account(
|
|||||||
|
|
||||||
// Only keep in cache the GiftWrap for the account.
|
// Only keep in cache the GiftWrap for the account.
|
||||||
if (it.recipientPubKey() == keyPair.pubKey.toHexKey()) {
|
if (it.recipientPubKey() == keyPair.pubKey.toHexKey()) {
|
||||||
|
if (loginWithAmber) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(it.content, it.pubKey, it.id, SignerType.NIP44_DECRYPT)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[it.id] ?: ""
|
||||||
|
if (decryptedContent.isEmpty()) return
|
||||||
|
it.cachedGift(keyPair.pubKey, decryptedContent)?.let { cached ->
|
||||||
|
if (cached is SealedGossipEvent) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(cached.content, cached.pubKey, cached.id, SignerType.NIP44_DECRYPT)
|
||||||
|
val localDecryptedContent = AmberUtils.cachedDecryptedContent[cached.id] ?: ""
|
||||||
|
if (localDecryptedContent.isEmpty()) return
|
||||||
|
cached.cachedGossip(keyPair.pubKey, localDecryptedContent)?.let { gossip ->
|
||||||
|
LocalCache.justConsume(gossip, null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LocalCache.justConsume(it, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
it.cachedGift(keyPair.privKey!!)?.let {
|
it.cachedGift(keyPair.privKey!!)?.let {
|
||||||
if (it is SealedGossipEvent) {
|
if (it is SealedGossipEvent) {
|
||||||
it.cachedGossip(keyPair.privKey!!)?.let {
|
it.cachedGossip(keyPair.privKey!!)?.let {
|
||||||
@@ -1416,6 +1543,7 @@ class Account(
|
|||||||
LocalCache.justConsume(it, null)
|
LocalCache.justConsume(it, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LocalCache.consume(it, null)
|
LocalCache.consume(it, null)
|
||||||
}
|
}
|
||||||
@@ -2026,7 +2154,7 @@ class Account(
|
|||||||
AmberUtils.content
|
AmberUtils.content
|
||||||
} else {
|
} else {
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
AmberUtils.decrypt(content, keyPair.pubKey.toHexKey())
|
AmberUtils.decrypt(content, keyPair.pubKey.toHexKey(), blockList?.id ?: "")
|
||||||
if (AmberUtils.content.isBlank()) return
|
if (AmberUtils.content.isBlank()) return
|
||||||
val decryptedContent = AmberUtils.content
|
val decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
@@ -2110,7 +2238,7 @@ class Account(
|
|||||||
AmberUtils.content
|
AmberUtils.content
|
||||||
} else {
|
} else {
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
AmberUtils.decrypt(content, keyPair.pubKey.toHexKey())
|
AmberUtils.decrypt(content, keyPair.pubKey.toHexKey(), blockList.id)
|
||||||
if (AmberUtils.content.isBlank()) return
|
if (AmberUtils.content.isBlank()) return
|
||||||
val decryptedContent = AmberUtils.content
|
val decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
@@ -2356,12 +2484,30 @@ class Account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun unwrap(event: GiftWrapEvent): Event? {
|
fun unwrap(event: GiftWrapEvent): Event? {
|
||||||
if (!isWriteable()) return null
|
if (!isWriteable() && !loginWithAmber) return null
|
||||||
|
|
||||||
|
if (loginWithAmber) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(event.content, event.pubKey, event.id, SignerType.NIP44_DECRYPT)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isEmpty()) return null
|
||||||
|
return event.cachedGift(keyPair.pubKey, decryptedContent)
|
||||||
|
}
|
||||||
|
|
||||||
return event.cachedGift(keyPair.privKey!!)
|
return event.cachedGift(keyPair.privKey!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unseal(event: SealedGossipEvent): Event? {
|
fun unseal(event: SealedGossipEvent): Event? {
|
||||||
if (!isWriteable()) return null
|
if (!isWriteable() && !loginWithAmber) return null
|
||||||
|
|
||||||
|
if (loginWithAmber) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(event.content, event.pubKey, event.id, SignerType.NIP44_DECRYPT)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isEmpty()) return null
|
||||||
|
return event.cachedGossip(keyPair.pubKey, decryptedContent)
|
||||||
|
}
|
||||||
|
|
||||||
return event.cachedGossip(keyPair.privKey!!)
|
return event.cachedGossip(keyPair.privKey!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ object AmberUtils {
|
|||||||
data: String,
|
data: String,
|
||||||
type: SignerType,
|
type: SignerType,
|
||||||
intentResult: ActivityResultLauncher<Intent>,
|
intentResult: ActivityResultLauncher<Intent>,
|
||||||
pubKey: HexKey
|
pubKey: HexKey,
|
||||||
|
id: String
|
||||||
) {
|
) {
|
||||||
ServiceManager.shouldPauseService = false
|
ServiceManager.shouldPauseService = false
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$data"))
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$data"))
|
||||||
@@ -31,6 +32,7 @@ object AmberUtils {
|
|||||||
}
|
}
|
||||||
intent.putExtra("type", signerType)
|
intent.putExtra("type", signerType)
|
||||||
intent.putExtra("pubKey", pubKey)
|
intent.putExtra("pubKey", pubKey)
|
||||||
|
intent.putExtra("id", id)
|
||||||
intent.`package` = "com.greenart7c3.nostrsigner.debug"
|
intent.`package` = "com.greenart7c3.nostrsigner.debug"
|
||||||
intentResult.launch(intent)
|
intentResult.launch(intent)
|
||||||
}
|
}
|
||||||
@@ -44,7 +46,8 @@ object AmberUtils {
|
|||||||
event.toJson(),
|
event.toJson(),
|
||||||
SignerType.SIGN_EVENT,
|
SignerType.SIGN_EVENT,
|
||||||
IntentUtils.activityResultLauncher,
|
IntentUtils.activityResultLauncher,
|
||||||
""
|
"",
|
||||||
|
event.id()
|
||||||
)
|
)
|
||||||
while (isActivityRunning) {
|
while (isActivityRunning) {
|
||||||
// do nothing
|
// do nothing
|
||||||
@@ -59,6 +62,7 @@ object AmberUtils {
|
|||||||
"",
|
"",
|
||||||
SignerType.GET_PUBLIC_KEY,
|
SignerType.GET_PUBLIC_KEY,
|
||||||
IntentUtils.activityResultLauncher,
|
IntentUtils.activityResultLauncher,
|
||||||
|
"",
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
while (isActivityRunning) {
|
while (isActivityRunning) {
|
||||||
@@ -66,14 +70,15 @@ object AmberUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(encryptedContent: String, pubKey: HexKey) {
|
fun decrypt(encryptedContent: String, pubKey: HexKey, id: String, signerType: SignerType = SignerType.NIP04_DECRYPT) {
|
||||||
if (content.isBlank()) {
|
if (content.isBlank()) {
|
||||||
isActivityRunning = true
|
isActivityRunning = true
|
||||||
openAmber(
|
openAmber(
|
||||||
encryptedContent,
|
encryptedContent,
|
||||||
SignerType.NIP04_DECRYPT,
|
signerType,
|
||||||
IntentUtils.activityResultLauncher,
|
IntentUtils.activityResultLauncher,
|
||||||
pubKey
|
pubKey,
|
||||||
|
id
|
||||||
)
|
)
|
||||||
while (isActivityRunning) {
|
while (isActivityRunning) {
|
||||||
// do nothing
|
// do nothing
|
||||||
@@ -81,14 +86,15 @@ object AmberUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encrypt(decryptedContent: String, pubKey: HexKey) {
|
fun encrypt(decryptedContent: String, pubKey: HexKey, signerType: SignerType = SignerType.NIP04_ENCRYPT) {
|
||||||
if (content.isBlank()) {
|
if (content.isBlank()) {
|
||||||
isActivityRunning = true
|
isActivityRunning = true
|
||||||
openAmber(
|
openAmber(
|
||||||
decryptedContent,
|
decryptedContent,
|
||||||
SignerType.NIP04_ENCRYPT,
|
signerType,
|
||||||
IntentUtils.activityResultLauncher,
|
IntentUtils.activityResultLauncher,
|
||||||
pubKey
|
pubKey,
|
||||||
|
""
|
||||||
)
|
)
|
||||||
while (isActivityRunning) {
|
while (isActivityRunning) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ object IntentUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val event = it.data?.getStringExtra("signature") ?: ""
|
val event = it.data?.getStringExtra("signature") ?: ""
|
||||||
|
val id = it.data?.getStringExtra("id") ?: ""
|
||||||
|
if (id.isNotBlank()) {
|
||||||
|
AmberUtils.cachedDecryptedContent[id] = event
|
||||||
|
}
|
||||||
AmberUtils.content = event
|
AmberUtils.content = event
|
||||||
AmberUtils.isActivityRunning = false
|
AmberUtils.isActivityRunning = false
|
||||||
ServiceManager.shouldPauseService = true
|
ServiceManager.shouldPauseService = true
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.vitorpamplona.amethyst.service.relays.EOSEAccount
|
|||||||
import com.vitorpamplona.amethyst.service.relays.JsonFilter
|
import com.vitorpamplona.amethyst.service.relays.JsonFilter
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
import com.vitorpamplona.amethyst.service.relays.TypedFilter
|
import com.vitorpamplona.amethyst.service.relays.TypedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.SignerType
|
||||||
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
|
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
|
||||||
import com.vitorpamplona.quartz.events.BadgeAwardEvent
|
import com.vitorpamplona.quartz.events.BadgeAwardEvent
|
||||||
import com.vitorpamplona.quartz.events.BadgeProfilesEvent
|
import com.vitorpamplona.quartz.events.BadgeProfilesEvent
|
||||||
@@ -29,6 +30,10 @@ import com.vitorpamplona.quartz.events.RepostEvent
|
|||||||
import com.vitorpamplona.quartz.events.SealedGossipEvent
|
import com.vitorpamplona.quartz.events.SealedGossipEvent
|
||||||
import com.vitorpamplona.quartz.events.StatusEvent
|
import com.vitorpamplona.quartz.events.StatusEvent
|
||||||
import com.vitorpamplona.quartz.events.TextNoteEvent
|
import com.vitorpamplona.quartz.events.TextNoteEvent
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object NostrAccountDataSource : NostrDataSource("AccountData") {
|
object NostrAccountDataSource : NostrDataSource("AccountData") {
|
||||||
lateinit var account: Account
|
lateinit var account: Account
|
||||||
@@ -144,6 +149,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
latestEOSEs.addOrUpdate(account.userProfile(), account.defaultNotificationFollowList, relayUrl, time)
|
latestEOSEs.addOrUpdate(account.userProfile(), account.defaultNotificationFollowList, relayUrl, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
override fun consume(event: Event, relay: Relay) {
|
override fun consume(event: Event, relay: Relay) {
|
||||||
if (LocalCache.justVerify(event)) {
|
if (LocalCache.justVerify(event)) {
|
||||||
if (event is GiftWrapEvent) {
|
if (event is GiftWrapEvent) {
|
||||||
@@ -152,6 +158,17 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
event.cachedGift(privateKey)?.let {
|
event.cachedGift(privateKey)?.let {
|
||||||
this.consume(it, relay)
|
this.consume(it, relay)
|
||||||
}
|
}
|
||||||
|
} else if (account.loginWithAmber) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(event.content, event.pubKey, event.id, SignerType.NIP44_DECRYPT)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isNotBlank()) {
|
||||||
|
event.cachedGift(account.keyPair.pubKey, decryptedContent)?.let {
|
||||||
|
consume(it, relay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +178,22 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
event.cachedGossip(privateKey)?.let {
|
event.cachedGossip(privateKey)?.let {
|
||||||
LocalCache.justConsume(it, relay)
|
LocalCache.justConsume(it, relay)
|
||||||
}
|
}
|
||||||
|
} else if (account.loginWithAmber) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(
|
||||||
|
event.content,
|
||||||
|
event.pubKey,
|
||||||
|
event.id,
|
||||||
|
SignerType.NIP44_DECRYPT
|
||||||
|
)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isNotBlank()) {
|
||||||
|
event.cachedGossip(account.keyPair.pubKey, decryptedContent)?.let {
|
||||||
|
LocalCache.justConsume(it, relay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't store sealed gossips to avoid rebroadcasting by mistake.
|
// Don't store sealed gossips to avoid rebroadcasting by mistake.
|
||||||
|
|||||||
+46
-2
@@ -7,8 +7,10 @@ import com.vitorpamplona.amethyst.LocalPreferences
|
|||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
import com.vitorpamplona.amethyst.service.AmberUtils
|
||||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification
|
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification
|
||||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification
|
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.SignerType
|
||||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||||
import com.vitorpamplona.quartz.events.ChatMessageEvent
|
import com.vitorpamplona.quartz.events.ChatMessageEvent
|
||||||
@@ -47,18 +49,60 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
|
|
||||||
return when (event) {
|
return when (event) {
|
||||||
is GiftWrapEvent -> {
|
is GiftWrapEvent -> {
|
||||||
val key = account.keyPair.privKey ?: return null
|
val key = account.keyPair.privKey
|
||||||
|
if (key != null) {
|
||||||
event.cachedGift(key)?.let {
|
event.cachedGift(key)?.let {
|
||||||
unwrapAndConsume(it, account)
|
unwrapAndConsume(it, account)
|
||||||
}
|
}
|
||||||
|
} else if (account.loginWithAmber) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(
|
||||||
|
event.content,
|
||||||
|
event.pubKey,
|
||||||
|
event.id,
|
||||||
|
SignerType.NIP44_DECRYPT
|
||||||
|
)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isNotBlank()) {
|
||||||
|
event.cachedGift(account.keyPair.pubKey, decryptedContent)?.let {
|
||||||
|
LocalCache.justConsume(it, null)
|
||||||
|
it
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is SealedGossipEvent -> {
|
is SealedGossipEvent -> {
|
||||||
val key = account.keyPair.privKey ?: return null
|
val key = account.keyPair.privKey
|
||||||
|
if (key != null) {
|
||||||
event.cachedGossip(key)?.let {
|
event.cachedGossip(key)?.let {
|
||||||
// this is not verifiable
|
// this is not verifiable
|
||||||
LocalCache.justConsume(it, null)
|
LocalCache.justConsume(it, null)
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
} else if (account.loginWithAmber) {
|
||||||
|
AmberUtils.content = ""
|
||||||
|
AmberUtils.decrypt(
|
||||||
|
event.content,
|
||||||
|
event.pubKey,
|
||||||
|
event.id,
|
||||||
|
SignerType.NIP44_DECRYPT
|
||||||
|
)
|
||||||
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
if (decryptedContent.isNotBlank()) {
|
||||||
|
event.cachedGossip(account.keyPair.pubKey, decryptedContent)?.let {
|
||||||
|
LocalCache.justConsume(it, null)
|
||||||
|
it
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
LocalCache.justConsume(event, null)
|
LocalCache.justConsume(event, null)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ fun SignerDialog(
|
|||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
AmberUtils.openAmber(data, type, intentResult, pubKey)
|
AmberUtils.openAmber(data, type, intentResult, pubKey, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog(
|
Dialog(
|
||||||
@@ -178,7 +178,7 @@ fun SignerDialog(
|
|||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
shape = ButtonBorder,
|
shape = ButtonBorder,
|
||||||
onClick = { AmberUtils.openAmber(data, type, intentResult, pubKey) }
|
onClick = { AmberUtils.openAmber(data, type, intentResult, pubKey, "") }
|
||||||
) {
|
) {
|
||||||
Text("Open Amber")
|
Text("Open Amber")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ object BookmarkPrivateFeedFilter : FeedFilter<Note>() {
|
|||||||
|
|
||||||
if (account.loginWithAmber) {
|
if (account.loginWithAmber) {
|
||||||
if (AmberUtils.content.isBlank()) {
|
if (AmberUtils.content.isBlank()) {
|
||||||
AmberUtils.decrypt(bookmarks?.content ?: "", account.keyPair.pubKey.toHexKey())
|
AmberUtils.decrypt(bookmarks?.content ?: "", account.keyPair.pubKey.toHexKey(), "")
|
||||||
bookmarks?.decryptedContent = AmberUtils.content
|
bookmarks?.decryptedContent = AmberUtils.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,8 @@ private fun UserRoomCompose(
|
|||||||
event?.content() ?: "",
|
event?.content() ?: "",
|
||||||
SignerType.NIP04_DECRYPT,
|
SignerType.NIP04_DECRYPT,
|
||||||
activityLauncher,
|
activityLauncher,
|
||||||
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex)
|
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex),
|
||||||
|
event.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -668,7 +668,8 @@ private fun RenderRegularTextNote(
|
|||||||
event?.content() ?: "",
|
event?.content() ?: "",
|
||||||
SignerType.NIP04_DECRYPT,
|
SignerType.NIP04_DECRYPT,
|
||||||
activityLauncher,
|
activityLauncher,
|
||||||
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex)
|
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex),
|
||||||
|
event.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1596,7 +1596,8 @@ private fun RenderPrivateMessage(
|
|||||||
event?.content() ?: "",
|
event?.content() ?: "",
|
||||||
SignerType.NIP04_DECRYPT,
|
SignerType.NIP04_DECRYPT,
|
||||||
activityLauncher,
|
activityLauncher,
|
||||||
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex)
|
(event as PrivateDmEvent).talkingWith(accountViewModel.userProfile().pubkeyHex),
|
||||||
|
event.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,7 +452,8 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState<Boolean>, accountVi
|
|||||||
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
||||||
AmberUtils.decrypt(
|
AmberUtils.decrypt(
|
||||||
bookmarks?.content ?: "",
|
bookmarks?.content ?: "",
|
||||||
accountViewModel.account.keyPair.pubKey.toHexKey()
|
accountViewModel.account.keyPair.pubKey.toHexKey(),
|
||||||
|
bookmarks?.id ?: ""
|
||||||
)
|
)
|
||||||
bookmarks?.decryptedContent = AmberUtils.content
|
bookmarks?.decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
@@ -474,7 +475,8 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState<Boolean>, accountVi
|
|||||||
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
||||||
AmberUtils.decrypt(
|
AmberUtils.decrypt(
|
||||||
bookmarks?.content ?: "",
|
bookmarks?.content ?: "",
|
||||||
accountViewModel.account.keyPair.pubKey.toHexKey()
|
accountViewModel.account.keyPair.pubKey.toHexKey(),
|
||||||
|
bookmarks?.id ?: ""
|
||||||
)
|
)
|
||||||
bookmarks?.decryptedContent = AmberUtils.content
|
bookmarks?.decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
@@ -497,7 +499,8 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState<Boolean>, accountVi
|
|||||||
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
||||||
AmberUtils.decrypt(
|
AmberUtils.decrypt(
|
||||||
bookmarks?.content ?: "",
|
bookmarks?.content ?: "",
|
||||||
accountViewModel.account.keyPair.pubKey.toHexKey()
|
accountViewModel.account.keyPair.pubKey.toHexKey(),
|
||||||
|
bookmarks?.id ?: ""
|
||||||
)
|
)
|
||||||
bookmarks?.decryptedContent = AmberUtils.content
|
bookmarks?.decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
@@ -522,7 +525,8 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState<Boolean>, accountVi
|
|||||||
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
val bookmarks = accountViewModel.userProfile().latestBookmarkList
|
||||||
AmberUtils.decrypt(
|
AmberUtils.decrypt(
|
||||||
bookmarks?.content ?: "",
|
bookmarks?.content ?: "",
|
||||||
accountViewModel.account.keyPair.pubKey.toHexKey()
|
accountViewModel.account.keyPair.pubKey.toHexKey(),
|
||||||
|
bookmarks?.id ?: ""
|
||||||
)
|
)
|
||||||
bookmarks?.decryptedContent = AmberUtils.content
|
bookmarks?.decryptedContent = AmberUtils.content
|
||||||
AmberUtils.content = ""
|
AmberUtils.content = ""
|
||||||
|
|||||||
@@ -296,7 +296,6 @@ fun ChatroomScreen(
|
|||||||
PrivateMessageEditFieldRow(newPostModel, isPrivate = true, accountViewModel) {
|
PrivateMessageEditFieldRow(newPostModel, isPrivate = true, accountViewModel) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
if (newPostModel.nip24 || room.users.size > 1 || replyTo.value?.event is ChatMessageEvent) {
|
if (newPostModel.nip24 || room.users.size > 1 || replyTo.value?.event is ChatMessageEvent) {
|
||||||
// TODO: add support for amber
|
|
||||||
accountViewModel.account.sendNIP24PrivateMessage(
|
accountViewModel.account.sendNIP24PrivateMessage(
|
||||||
message = newPostModel.message.text,
|
message = newPostModel.message.text,
|
||||||
toUsers = room.users.toList(),
|
toUsers = room.users.toList(),
|
||||||
@@ -639,7 +638,6 @@ fun NewSubjectView(onClose: () -> Unit, accountViewModel: AccountViewModel, room
|
|||||||
PostButton(
|
PostButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
// TODO: add support for amber
|
|
||||||
accountViewModel.account.sendNIP24PrivateMessage(
|
accountViewModel.account.sendNIP24PrivateMessage(
|
||||||
message = message.value,
|
message = message.value,
|
||||||
toUsers = room.users.toList(),
|
toUsers = room.users.toList(),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import androidx.compose.runtime.Stable
|
|||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||||
|
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
@@ -61,7 +62,7 @@ class ChatMessageEvent(
|
|||||||
markAsSensitive: Boolean = false,
|
markAsSensitive: Boolean = false,
|
||||||
zapRaiserAmount: Long? = null,
|
zapRaiserAmount: Long? = null,
|
||||||
geohash: String? = null,
|
geohash: String? = null,
|
||||||
privateKey: ByteArray,
|
keyPair: KeyPair,
|
||||||
createdAt: Long = TimeUtils.now()
|
createdAt: Long = TimeUtils.now()
|
||||||
): ChatMessageEvent {
|
): ChatMessageEvent {
|
||||||
val content = msg
|
val content = msg
|
||||||
@@ -91,10 +92,17 @@ class ChatMessageEvent(
|
|||||||
tags.add(listOf("subject", it))
|
tags.add(listOf("subject", it))
|
||||||
}
|
}
|
||||||
|
|
||||||
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
val pubKey = keyPair.pubKey.toHexKey()
|
||||||
val id = generateId(pubKey, createdAt, ClassifiedsEvent.kind, tags, content)
|
val id = generateId(pubKey, createdAt, ClassifiedsEvent.kind, tags, content)
|
||||||
val sig = CryptoUtils.sign(id, privateKey)
|
val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey)
|
||||||
return ChatMessageEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
|
return ChatMessageEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
unsignedEvent: ChatMessageEvent,
|
||||||
|
signature: String
|
||||||
|
): ChatMessageEvent {
|
||||||
|
return ChatMessageEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,19 @@ class GiftWrapEvent(
|
|||||||
return myInnerEvent
|
return myInnerEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cachedGift(pubKey: ByteArray, decryptedContent: String): Event? {
|
||||||
|
val hex = pubKey.toHexKey()
|
||||||
|
if (cachedInnerEvent.contains(hex)) return cachedInnerEvent[hex]
|
||||||
|
|
||||||
|
val myInnerEvent = unwrap(decryptedContent)
|
||||||
|
if (myInnerEvent is WrappedEvent) {
|
||||||
|
myInnerEvent.host = this
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedInnerEvent = cachedInnerEvent + Pair(hex, myInnerEvent)
|
||||||
|
return myInnerEvent
|
||||||
|
}
|
||||||
|
|
||||||
fun unwrap(privKey: ByteArray) = try {
|
fun unwrap(privKey: ByteArray) = try {
|
||||||
plainContent(privKey)?.let { fromJson(it) }
|
plainContent(privKey)?.let { fromJson(it) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -43,6 +56,13 @@ class GiftWrapEvent(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun unwrap(decryptedContent: String) = try {
|
||||||
|
plainContent(decryptedContent)?.let { fromJson(it) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Log.e("UnwrapError", "Couldn't Decrypt the content", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
private fun plainContent(privKey: ByteArray): String? {
|
private fun plainContent(privKey: ByteArray): String? {
|
||||||
if (content.isEmpty()) return null
|
if (content.isEmpty()) return null
|
||||||
|
|
||||||
@@ -60,6 +80,11 @@ class GiftWrapEvent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun plainContent(decryptedContent: String): String? {
|
||||||
|
if (decryptedContent.isEmpty()) return null
|
||||||
|
return decryptedContent
|
||||||
|
}
|
||||||
|
|
||||||
fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class NIP24Factory {
|
|||||||
fun createMsgNIP24(
|
fun createMsgNIP24(
|
||||||
msg: String,
|
msg: String,
|
||||||
to: List<HexKey>,
|
to: List<HexKey>,
|
||||||
from: ByteArray,
|
keyPair: KeyPair,
|
||||||
subject: String? = null,
|
subject: String? = null,
|
||||||
replyTos: List<String>? = null,
|
replyTos: List<String>? = null,
|
||||||
mentions: List<String>? = null,
|
mentions: List<String>? = null,
|
||||||
@@ -18,12 +18,12 @@ class NIP24Factory {
|
|||||||
zapRaiserAmount: Long? = null,
|
zapRaiserAmount: Long? = null,
|
||||||
geohash: String? = null
|
geohash: String? = null
|
||||||
): List<GiftWrapEvent> {
|
): List<GiftWrapEvent> {
|
||||||
val senderPublicKey = CryptoUtils.pubkeyCreate(from).toHexKey()
|
val senderPublicKey = keyPair.pubKey.toHexKey()
|
||||||
|
|
||||||
val senderMessage = ChatMessageEvent.create(
|
val senderMessage = ChatMessageEvent.create(
|
||||||
msg = msg,
|
msg = msg,
|
||||||
to = to,
|
to = to,
|
||||||
privateKey = from,
|
keyPair = keyPair,
|
||||||
subject = subject,
|
subject = subject,
|
||||||
replyTos = replyTos,
|
replyTos = replyTos,
|
||||||
mentions = mentions,
|
mentions = mentions,
|
||||||
@@ -38,7 +38,7 @@ class NIP24Factory {
|
|||||||
event = SealedGossipEvent.create(
|
event = SealedGossipEvent.create(
|
||||||
event = senderMessage,
|
event = senderMessage,
|
||||||
encryptTo = it,
|
encryptTo = it,
|
||||||
privateKey = from
|
privateKey = keyPair.privKey!!
|
||||||
),
|
),
|
||||||
recipientPubKey = it
|
recipientPubKey = it
|
||||||
)
|
)
|
||||||
@@ -46,7 +46,7 @@ class NIP24Factory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createReactionWithinGroup(content: String, originalNote: EventInterface, to: List<HexKey>, from: KeyPair): List<GiftWrapEvent> {
|
fun createReactionWithinGroup(content: String, originalNote: EventInterface, to: List<HexKey>, from: KeyPair): List<GiftWrapEvent> {
|
||||||
val senderPublicKey = CryptoUtils.pubkeyCreate(from.privKey!!).toHexKey()
|
val senderPublicKey = from.pubKey.toHexKey()
|
||||||
|
|
||||||
val senderReaction = ReactionEvent.create(
|
val senderReaction = ReactionEvent.create(
|
||||||
content,
|
content,
|
||||||
@@ -59,7 +59,7 @@ class NIP24Factory {
|
|||||||
event = SealedGossipEvent.create(
|
event = SealedGossipEvent.create(
|
||||||
event = senderReaction,
|
event = senderReaction,
|
||||||
encryptTo = it,
|
encryptTo = it,
|
||||||
privateKey = from.privKey
|
privateKey = from.privKey!!
|
||||||
),
|
),
|
||||||
recipientPubKey = it
|
recipientPubKey = it
|
||||||
)
|
)
|
||||||
@@ -67,7 +67,7 @@ class NIP24Factory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createReactionWithinGroup(emojiUrl: EmojiUrl, originalNote: EventInterface, to: List<HexKey>, from: KeyPair): List<GiftWrapEvent> {
|
fun createReactionWithinGroup(emojiUrl: EmojiUrl, originalNote: EventInterface, to: List<HexKey>, from: KeyPair): List<GiftWrapEvent> {
|
||||||
val senderPublicKey = CryptoUtils.pubkeyCreate(from.privKey!!).toHexKey()
|
val senderPublicKey = from.pubKey.toHexKey()
|
||||||
|
|
||||||
val senderReaction = ReactionEvent.create(
|
val senderReaction = ReactionEvent.create(
|
||||||
emojiUrl,
|
emojiUrl,
|
||||||
@@ -80,7 +80,7 @@ class NIP24Factory {
|
|||||||
event = SealedGossipEvent.create(
|
event = SealedGossipEvent.create(
|
||||||
event = senderReaction,
|
event = senderReaction,
|
||||||
encryptTo = it,
|
encryptTo = it,
|
||||||
privateKey = from.privKey
|
privateKey = from.privKey!!
|
||||||
),
|
),
|
||||||
recipientPubKey = it
|
recipientPubKey = it
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,6 +38,20 @@ class SealedGossipEvent(
|
|||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cachedGossip(pubKey: ByteArray, decryptedContent: String): Event? {
|
||||||
|
val hex = pubKey.toHexKey()
|
||||||
|
if (cachedInnerEvent.contains(hex)) return cachedInnerEvent[hex]
|
||||||
|
|
||||||
|
val gossip = unseal(decryptedContent)
|
||||||
|
val event = gossip?.mergeWith(this)
|
||||||
|
if (event is WrappedEvent) {
|
||||||
|
event.host = host ?: this
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedInnerEvent = cachedInnerEvent + Pair(hex, event)
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
fun unseal(privKey: ByteArray): Gossip? = try {
|
fun unseal(privKey: ByteArray): Gossip? = try {
|
||||||
plainContent(privKey)?.let { Gossip.fromJson(it) }
|
plainContent(privKey)?.let { Gossip.fromJson(it) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -45,6 +59,18 @@ class SealedGossipEvent(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun unseal(decryptedContent: String): Gossip? = try {
|
||||||
|
plainContent(decryptedContent)?.let { Gossip.fromJson(it) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w("GossipEvent", "Fail to decrypt or parse Gossip", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun plainContent(decryptedContent: String): String? {
|
||||||
|
if (decryptedContent.isEmpty()) return null
|
||||||
|
return decryptedContent
|
||||||
|
}
|
||||||
|
|
||||||
private fun plainContent(privKey: ByteArray): String? {
|
private fun plainContent(privKey: ByteArray): String? {
|
||||||
if (content.isEmpty()) return null
|
if (content.isEmpty()) return null
|
||||||
|
|
||||||
@@ -95,6 +121,23 @@ class SealedGossipEvent(
|
|||||||
val sig = CryptoUtils.sign(id, privateKey)
|
val sig = CryptoUtils.sign(id, privateKey)
|
||||||
return SealedGossipEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
|
return SealedGossipEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
encryptedContent: String,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long = TimeUtils.randomWithinAWeek()
|
||||||
|
): SealedGossipEvent {
|
||||||
|
val tags = listOf<List<String>>()
|
||||||
|
val id = generateId(pubKey, createdAt, kind, tags, encryptedContent)
|
||||||
|
return SealedGossipEvent(id.toHexKey(), pubKey, createdAt, tags, encryptedContent, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
unsignedEvent: SealedGossipEvent,
|
||||||
|
signature: String
|
||||||
|
): SealedGossipEvent {
|
||||||
|
return SealedGossipEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user