add support for private zaps

This commit is contained in:
greenart7c3 2023-09-11 15:30:00 -03:00
parent a773be12c4
commit ff4d704bde
5 changed files with 162 additions and 52 deletions

View File

@ -461,6 +461,21 @@ class Account(
AmberUtils.content
)
}
LnZapEvent.ZapType.PRIVATE -> {
val unsignedEvent = LnZapRequestEvent.createPrivateZap(
event,
userProfile().latestContactList?.relays()?.keys?.ifEmpty { null }
?: localRelays.map { it.url }.toSet(),
keyPair.pubKey.toHexKey(),
pollOption,
message
)
AmberUtils.content = ""
AmberUtils.openAmber(unsignedEvent)
if (AmberUtils.content.isBlank()) return null
return Event.fromJson(AmberUtils.content) as LnZapRequestEvent
}
else -> null
}
} else {
@ -485,10 +500,14 @@ class Account(
fun isNIP47Author(pubkeyHex: String?): Boolean {
val privKey = zapPaymentRequest?.secret?.hexToByteArray() ?: keyPair.privKey
if (privKey == null) return false
if (privKey == null && !loginWithAmber) return false
val pubKey = CryptoUtils.pubkeyCreate(privKey).toHexKey()
return (pubKey == pubkeyHex)
if (privKey != null) {
val pubKey = CryptoUtils.pubkeyCreate(privKey).toHexKey()
return (pubKey == pubkeyHex)
}
return (keyPair.pubKey.toHexKey() == pubkeyHex)
}
fun decryptZapPaymentResponseEvent(zapResponseEvent: LnZapPaymentResponseEvent): Response? {
@ -497,9 +516,14 @@ class Account(
val privKey = myNip47.secret?.hexToByteArray() ?: keyPair.privKey
val pubKey = myNip47.pubKeyHex.hexToByteArray()
if (privKey == null) return null
if (privKey == null && !loginWithAmber) return null
return zapResponseEvent.response(privKey, pubKey)
if (privKey != null) return zapResponseEvent.response(privKey, pubKey)
Log.d("zaps", "decrypt with amber")
AmberUtils.decrypt(zapResponseEvent.content, pubKey.toHexKey(), zapResponseEvent.id)
if (AmberUtils.content.isBlank()) return null
return zapResponseEvent.response(AmberUtils.content)
}
fun calculateIfNoteWasZappedByAccount(zappedNote: Note?): Boolean {
@ -2546,12 +2570,21 @@ class Account(
if (loginWithAmber && event is LnZapRequestEvent && event.isPrivateZap()) {
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id]
if (decryptedContent != null) {
return Event.fromJson(decryptedContent)
return try {
Event.fromJson(decryptedContent)
} catch (e: Exception) {
null
}
}
AmberUtils.decryptZapEvent(event)
if (AmberUtils.content.isBlank()) return null
if (AmberUtils.content == "Could not decrypt the message") return null
AmberUtils.cachedDecryptedContent[event.id] = AmberUtils.content
return Event.fromJson(AmberUtils.content)
return try {
Event.fromJson(AmberUtils.content)
} catch (e: Exception) {
null
}
}
return if (event is LnZapRequestEvent && loggedInPrivateKey != null && event.isPrivateZap()) {

View File

@ -105,18 +105,16 @@ object AmberUtils {
}
fun decryptZapEvent(event: LnZapRequestEvent) {
if (content.isBlank()) {
isActivityRunning = true
openAmber(
event.toJson(),
SignerType.DECRYPT_ZAP_EVENT,
IntentUtils.activityResultLauncher,
event.pubKey,
event.id
)
while (isActivityRunning) {
// do nothing
}
isActivityRunning = true
openAmber(
event.toJson(),
SignerType.DECRYPT_ZAP_EVENT,
IntentUtils.activityResultLauncher,
event.pubKey,
event.id
)
while (isActivityRunning) {
// do nothing
}
}
}

View File

@ -34,27 +34,57 @@ class EventNotificationConsumer(private val applicationContext: Context) {
// Test with all logged in accounts
LocalPreferences.allSavedAccounts().forEach {
val acc = LocalPreferences.loadFromEncryptedStorage(it.npub)
if (acc != null && acc.keyPair.privKey != null) {
if (acc != null && (acc.keyPair.privKey != null || acc.loginWithAmber)) {
consumeIfMatchesAccount(event, acc)
}
}
}
private suspend fun consumeIfMatchesAccount(pushWrappedEvent: GiftWrapEvent, account: Account) {
val key = account.keyPair.privKey ?: return
pushWrappedEvent.unwrap(key)?.let { notificationEvent ->
if (!LocalCache.justVerify(notificationEvent)) return // invalid event
if (LocalCache.notes[notificationEvent.id] != null) return // already processed
val key = account.keyPair.privKey
if (account.loginWithAmber) {
var cached = AmberUtils.cachedDecryptedContent[pushWrappedEvent.id]
if (cached == null) {
AmberUtils.content = ""
AmberUtils.decrypt(
pushWrappedEvent.content,
pushWrappedEvent.pubKey,
pushWrappedEvent.id,
SignerType.NIP44_DECRYPT
)
cached = AmberUtils.cachedDecryptedContent[pushWrappedEvent.id] ?: ""
}
pushWrappedEvent.unwrap(cached)?.let { notificationEvent ->
if (!LocalCache.justVerify(notificationEvent)) return // invalid event
if (LocalCache.notes[notificationEvent.id] != null) return // already processed
LocalCache.justConsume(notificationEvent, null)
LocalCache.justConsume(notificationEvent, null)
unwrapAndConsume(notificationEvent, account)?.let { innerEvent ->
if (innerEvent is PrivateDmEvent) {
notify(innerEvent, account)
} else if (innerEvent is LnZapEvent) {
notify(innerEvent, account)
} else if (innerEvent is ChatMessageEvent) {
notify(innerEvent, account)
unwrapAndConsume(notificationEvent, account)?.let { innerEvent ->
if (innerEvent is PrivateDmEvent) {
notify(innerEvent, account)
} else if (innerEvent is LnZapEvent) {
notify(innerEvent, account)
} else if (innerEvent is ChatMessageEvent) {
notify(innerEvent, account)
}
}
}
} else if (key != null) {
pushWrappedEvent.unwrap(key)?.let { notificationEvent ->
if (!LocalCache.justVerify(notificationEvent)) return // invalid event
if (LocalCache.notes[notificationEvent.id] != null) return // already processed
LocalCache.justConsume(notificationEvent, null)
unwrapAndConsume(notificationEvent, account)?.let { innerEvent ->
if (innerEvent is PrivateDmEvent) {
notify(innerEvent, account)
} else if (innerEvent is LnZapEvent) {
notify(innerEvent, account)
} else if (innerEvent is ChatMessageEvent) {
notify(innerEvent, account)
}
}
}
}
@ -71,16 +101,20 @@ class EventNotificationConsumer(private val applicationContext: Context) {
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 {
var cached = AmberUtils.cachedDecryptedContent[event.id]
if (cached == null) {
AmberUtils.content = ""
AmberUtils.decrypt(
event.content,
event.pubKey,
event.id,
SignerType.NIP44_DECRYPT
)
cached = AmberUtils.cachedDecryptedContent[event.id] ?: ""
}
if (cached.isNotBlank()) {
event.cachedGift(account.keyPair.pubKey, cached)?.let {
LocalCache.justConsume(it, null)
it
}
@ -100,16 +134,19 @@ class EventNotificationConsumer(private val applicationContext: Context) {
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 {
var cached = AmberUtils.cachedDecryptedContent[event.id]
if (cached == null) {
AmberUtils.content = ""
AmberUtils.decrypt(
event.content,
event.pubKey,
event.id,
SignerType.NIP44_DECRYPT
)
cached = AmberUtils.cachedDecryptedContent[event.id] ?: ""
}
if (cached.isNotBlank()) {
event.cachedGossip(account.keyPair.pubKey, cached)?.let {
LocalCache.justConsume(it, null)
it
}

View File

@ -61,6 +61,22 @@ class LnZapPaymentResponseEvent(
}
}
fun response(decryptedContent: String): Response? {
if (response != null) response
return try {
if (content.isNotEmpty()) {
response = mapper.readValue(decryptedContent, Response::class.java)
response
} else {
null
}
} catch (e: Exception) {
Log.w("LnZapPaymentResponseEvent", "Can't parse content as a payment response: $content", e)
null
}
}
companion object {
const val kind = 23195
}

View File

@ -123,6 +123,32 @@ class LnZapRequestEvent(
return LnZapRequestEvent(id.toHexKey(), pubKey, createdAt, tags, message, "")
}
fun createPrivateZap(
originalNote: EventInterface,
relays: Set<String>,
pubKey: HexKey,
pollOption: Int?,
message: String,
createdAt: Long = TimeUtils.now()
): LnZapRequestEvent {
val content = message
var tags = listOf(
listOf("e", originalNote.id()),
listOf("p", originalNote.pubKey()),
listOf("relays") + relays
)
if (originalNote is AddressableEvent) {
tags = tags + listOf(listOf("a", originalNote.address().toTag()))
}
if (pollOption != null && pollOption >= 0) {
tags = tags + listOf(listOf(POLL_OPTION, pollOption.toString()))
}
tags = tags + listOf(listOf("anon", ""))
return LnZapRequestEvent("", pubKey, createdAt, tags, content, "")
}
fun createAnonymous(
originalNote: EventInterface,
relays: Set<String>,