Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions app/src/main/kotlin/com/wisp/app/nostr/Nip78.kt
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,48 @@ object Nip78 {
/** Extract the d-tag value from an event, or null. */
fun extractDTag(event: NostrEvent): String? =
event.tags.firstOrNull { it.size >= 2 && it[0] == "d" }?.get(1)

// ─── NWC connection backup ────────────────────────────────────────
//
// Cross-platform NWC URI backup per `NWC_BACKUP_PARITY.md`. iOS
// and Android both publish to / read from the same flat `d` tag
// (`nwc-wallet-backup` — no `wisp-` prefix, intentional, for
// cross-platform interop). Content is the raw NWC URI string,
// NIP-44 v2 encrypted to self.

const val NWC_BACKUP_D_TAG = "nwc-wallet-backup"

/** Build + sign a kind-30078 event carrying the encrypted NWC URI. */
suspend fun createNwcBackupEvent(signer: NostrSigner, uri: String): NostrEvent {
val encrypted = signer.nip44Encrypt(uri.trim(), signer.pubkeyHex)
val tags = listOf(
listOf("d", NWC_BACKUP_D_TAG),
listOf("client", "Wisp"),
listOf("encryption", "nip44")
)
return signer.signEvent(kind = KIND, content = encrypted, tags = tags)
}

/**
* Decrypt a kind-30078 NWC-backup event and return the raw URI.
* Returns null when the content is empty, decrypt fails, or the
* plaintext doesn't look like a `nostr+walletconnect://` URI.
*/
suspend fun decryptNwcBackup(signer: NostrSigner, event: NostrEvent): String? {
if (event.content.isBlank()) return null
return try {
val decrypted = signer.nip44Decrypt(event.content, event.pubkey).trim()
if (decrypted.startsWith("nostr+walletconnect://", ignoreCase = true)) decrypted else null
} catch (_: Exception) {
null
}
}

/** Filter to fetch the user's NWC backup (single addressable event). */
fun nwcBackupFilter(pubkeyHex: String): Filter = Filter(
kinds = listOf(KIND),
authors = listOf(pubkeyHex),
dTags = listOf(NWC_BACKUP_D_TAG),
limit = 1
)
}
Loading