add support for private zaps
This commit is contained in:
@@ -461,6 +461,21 @@ class Account(
|
|||||||
AmberUtils.content
|
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 -> null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -485,10 +500,14 @@ class Account(
|
|||||||
fun isNIP47Author(pubkeyHex: String?): Boolean {
|
fun isNIP47Author(pubkeyHex: String?): Boolean {
|
||||||
val privKey = zapPaymentRequest?.secret?.hexToByteArray() ?: keyPair.privKey
|
val privKey = zapPaymentRequest?.secret?.hexToByteArray() ?: keyPair.privKey
|
||||||
|
|
||||||
if (privKey == null) return false
|
if (privKey == null && !loginWithAmber) return false
|
||||||
|
|
||||||
val pubKey = CryptoUtils.pubkeyCreate(privKey).toHexKey()
|
if (privKey != null) {
|
||||||
return (pubKey == pubkeyHex)
|
val pubKey = CryptoUtils.pubkeyCreate(privKey).toHexKey()
|
||||||
|
return (pubKey == pubkeyHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (keyPair.pubKey.toHexKey() == pubkeyHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decryptZapPaymentResponseEvent(zapResponseEvent: LnZapPaymentResponseEvent): Response? {
|
fun decryptZapPaymentResponseEvent(zapResponseEvent: LnZapPaymentResponseEvent): Response? {
|
||||||
@@ -497,9 +516,14 @@ class Account(
|
|||||||
val privKey = myNip47.secret?.hexToByteArray() ?: keyPair.privKey
|
val privKey = myNip47.secret?.hexToByteArray() ?: keyPair.privKey
|
||||||
val pubKey = myNip47.pubKeyHex.hexToByteArray()
|
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 {
|
fun calculateIfNoteWasZappedByAccount(zappedNote: Note?): Boolean {
|
||||||
@@ -2546,12 +2570,21 @@ class Account(
|
|||||||
if (loginWithAmber && event is LnZapRequestEvent && event.isPrivateZap()) {
|
if (loginWithAmber && event is LnZapRequestEvent && event.isPrivateZap()) {
|
||||||
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id]
|
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id]
|
||||||
if (decryptedContent != null) {
|
if (decryptedContent != null) {
|
||||||
return Event.fromJson(decryptedContent)
|
return try {
|
||||||
|
Event.fromJson(decryptedContent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AmberUtils.decryptZapEvent(event)
|
AmberUtils.decryptZapEvent(event)
|
||||||
if (AmberUtils.content.isBlank()) return null
|
if (AmberUtils.content.isBlank()) return null
|
||||||
|
if (AmberUtils.content == "Could not decrypt the message") return null
|
||||||
AmberUtils.cachedDecryptedContent[event.id] = AmberUtils.content
|
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()) {
|
return if (event is LnZapRequestEvent && loggedInPrivateKey != null && event.isPrivateZap()) {
|
||||||
|
|||||||
@@ -105,18 +105,16 @@ object AmberUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun decryptZapEvent(event: LnZapRequestEvent) {
|
fun decryptZapEvent(event: LnZapRequestEvent) {
|
||||||
if (content.isBlank()) {
|
isActivityRunning = true
|
||||||
isActivityRunning = true
|
openAmber(
|
||||||
openAmber(
|
event.toJson(),
|
||||||
event.toJson(),
|
SignerType.DECRYPT_ZAP_EVENT,
|
||||||
SignerType.DECRYPT_ZAP_EVENT,
|
IntentUtils.activityResultLauncher,
|
||||||
IntentUtils.activityResultLauncher,
|
event.pubKey,
|
||||||
event.pubKey,
|
event.id
|
||||||
event.id
|
)
|
||||||
)
|
while (isActivityRunning) {
|
||||||
while (isActivityRunning) {
|
// do nothing
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-33
@@ -34,27 +34,57 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
// Test with all logged in accounts
|
// Test with all logged in accounts
|
||||||
LocalPreferences.allSavedAccounts().forEach {
|
LocalPreferences.allSavedAccounts().forEach {
|
||||||
val acc = LocalPreferences.loadFromEncryptedStorage(it.npub)
|
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)
|
consumeIfMatchesAccount(event, acc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun consumeIfMatchesAccount(pushWrappedEvent: GiftWrapEvent, account: Account) {
|
private suspend fun consumeIfMatchesAccount(pushWrappedEvent: GiftWrapEvent, account: Account) {
|
||||||
val key = account.keyPair.privKey ?: return
|
val key = account.keyPair.privKey
|
||||||
pushWrappedEvent.unwrap(key)?.let { notificationEvent ->
|
if (account.loginWithAmber) {
|
||||||
if (!LocalCache.justVerify(notificationEvent)) return // invalid event
|
var cached = AmberUtils.cachedDecryptedContent[pushWrappedEvent.id]
|
||||||
if (LocalCache.notes[notificationEvent.id] != null) return // already processed
|
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 ->
|
unwrapAndConsume(notificationEvent, account)?.let { innerEvent ->
|
||||||
if (innerEvent is PrivateDmEvent) {
|
if (innerEvent is PrivateDmEvent) {
|
||||||
notify(innerEvent, account)
|
notify(innerEvent, account)
|
||||||
} else if (innerEvent is LnZapEvent) {
|
} else if (innerEvent is LnZapEvent) {
|
||||||
notify(innerEvent, account)
|
notify(innerEvent, account)
|
||||||
} else if (innerEvent is ChatMessageEvent) {
|
} else if (innerEvent is ChatMessageEvent) {
|
||||||
notify(innerEvent, account)
|
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)
|
unwrapAndConsume(it, account)
|
||||||
}
|
}
|
||||||
} else if (account.loginWithAmber) {
|
} else if (account.loginWithAmber) {
|
||||||
AmberUtils.content = ""
|
var cached = AmberUtils.cachedDecryptedContent[event.id]
|
||||||
AmberUtils.decrypt(
|
if (cached == null) {
|
||||||
event.content,
|
AmberUtils.content = ""
|
||||||
event.pubKey,
|
AmberUtils.decrypt(
|
||||||
event.id,
|
event.content,
|
||||||
SignerType.NIP44_DECRYPT
|
event.pubKey,
|
||||||
)
|
event.id,
|
||||||
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
SignerType.NIP44_DECRYPT
|
||||||
if (decryptedContent.isNotBlank()) {
|
)
|
||||||
event.cachedGift(account.keyPair.pubKey, decryptedContent)?.let {
|
cached = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cached.isNotBlank()) {
|
||||||
|
event.cachedGift(account.keyPair.pubKey, cached)?.let {
|
||||||
LocalCache.justConsume(it, null)
|
LocalCache.justConsume(it, null)
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
@@ -100,16 +134,19 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
it
|
it
|
||||||
}
|
}
|
||||||
} else if (account.loginWithAmber) {
|
} else if (account.loginWithAmber) {
|
||||||
AmberUtils.content = ""
|
var cached = AmberUtils.cachedDecryptedContent[event.id]
|
||||||
AmberUtils.decrypt(
|
if (cached == null) {
|
||||||
event.content,
|
AmberUtils.content = ""
|
||||||
event.pubKey,
|
AmberUtils.decrypt(
|
||||||
event.id,
|
event.content,
|
||||||
SignerType.NIP44_DECRYPT
|
event.pubKey,
|
||||||
)
|
event.id,
|
||||||
val decryptedContent = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
SignerType.NIP44_DECRYPT
|
||||||
if (decryptedContent.isNotBlank()) {
|
)
|
||||||
event.cachedGossip(account.keyPair.pubKey, decryptedContent)?.let {
|
cached = AmberUtils.cachedDecryptedContent[event.id] ?: ""
|
||||||
|
}
|
||||||
|
if (cached.isNotBlank()) {
|
||||||
|
event.cachedGossip(account.keyPair.pubKey, cached)?.let {
|
||||||
LocalCache.justConsume(it, null)
|
LocalCache.justConsume(it, null)
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
companion object {
|
||||||
const val kind = 23195
|
const val kind = 23195
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,32 @@ class LnZapRequestEvent(
|
|||||||
return LnZapRequestEvent(id.toHexKey(), pubKey, createdAt, tags, message, "")
|
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(
|
fun createAnonymous(
|
||||||
originalNote: EventInterface,
|
originalNote: EventInterface,
|
||||||
relays: Set<String>,
|
relays: Set<String>,
|
||||||
|
|||||||
Reference in New Issue
Block a user