Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
local.properties
# AI
.ai
.codex/
.claude/worktrees
*.local.*
!*.local.template*
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/to/bitkit/data/PrivatePaykitStores.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ data class PrivatePaykitCacheData(
val contacts: Map<String, PrivatePaykitContactCacheData> = emptyMap(),
val cleanupPending: Boolean = false,
val deletedContactCleanupPendingPublicKeys: Set<String> = emptySet(),
val profileRecoveryPending: Boolean = false,
)

@Serializable
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/data/SettingsStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ data class SettingsData(
val hasSeenContactsIntro: Boolean = false,
val hasConfirmedPublicPaykitEndpoints: Boolean = false,
val sharesPublicPaykitEndpoints: Boolean = false,
val sharesPrivatePaykitEndpoints: Boolean = false,
val publicPaykitLightningEnabled: Boolean = true,
val publicPaykitOnchainEnabled: Boolean = true,
val publicPaykitBolt11: String = "",
val publicPaykitBolt11PaymentHash: String = "",
val publicPaykitBolt11ExpiresAtMillis: Long = 0,
Expand Down
34 changes: 32 additions & 2 deletions app/src/main/java/to/bitkit/repositories/ActivityRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,39 @@ class ActivityRepo @Inject constructor(
}
}

suspend fun clearContact(
forPaymentId: String,
syncLdkPayments: Boolean = true,
): Result<Unit> = withContext(ioDispatcher) {
runCatching {
if (syncLdkPayments) {
lightningRepo.getPayments().onSuccess {
syncLdkNodePayments(it).getOrThrow()
}.getOrThrow()
}

val activity = findActivityForPaymentId(forPaymentId, syncLdkPayments)
if (activity == null) {
Logger.warn(
"Skipped clearing contact for payment '$forPaymentId' because activity was not found",
context = TAG,
)
return@runCatching
}
if (activity.contact() == null) return@runCatching

val updatedAt = nowTimestamp().epochSecond.toULong()
val updatedActivity = activity.withContact(null, updatedAt)
updateActivity(updatedActivity.rawId(), updatedActivity).getOrThrow()
updateReplacementContactIfNeeded(updatedActivity, null, updatedAt)
}.onFailure {
Logger.error("Failed to clear contact for payment '$forPaymentId'", it, context = TAG)
}
}

private suspend fun updateReplacementContactIfNeeded(
activity: Activity,
normalizedKey: String,
normalizedKey: String?,
updatedAt: ULong,
) {
if (activity !is Activity.Onchain || activity.v1.doesExist || activity.v1.txType != PaymentType.SENT) return
Expand Down Expand Up @@ -422,7 +452,7 @@ class ActivityRepo @Inject constructor(
coreService.activity.getActivity(forPaymentId)
?: getOnchainActivityByTxId(forPaymentId)?.let { Activity.Onchain(it) }

private fun Activity.withContact(normalizedKey: String, updatedAt: ULong): Activity = when (this) {
private fun Activity.withContact(normalizedKey: String?, updatedAt: ULong): Activity = when (this) {
is Activity.Lightning -> Activity.Lightning(v1.copy(contact = normalizedKey, updatedAt = updatedAt))
is Activity.Onchain -> Activity.Onchain(v1.copy(contact = normalizedKey, updatedAt = updatedAt))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal object PrivatePaykitErrorClassifier {

private fun isNoiseStateFailure(reason: String): Boolean {
val lowercasedReason = reason.lowercase()
return listOf("decrypt", "decryption", "cipher", "noise state", "counter", "invalid tag", "bad mac")
return listOf("decrypt", "decryption", "cipher", "invalid tag", "bad mac")
.any { it in lowercasedReason }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import to.bitkit.utils.AppError
sealed class PrivatePaykitError(message: String, cause: Throwable? = null) : AppError(message, cause) {
data object PrivateUnavailable : PrivatePaykitError("Private Paykit is not available")
data object PayloadTooLarge : PrivatePaykitError("Private Paykit payload is too large")
data object RouteHintsUnavailable : PrivatePaykitError("Reachable private Lightning endpoint is not available yet")
data object SnapshotRecipientMismatch : PrivatePaykitError("Private Paykit snapshot recipient mismatch")
data object StaleLinkState : PrivatePaykitError("Private Paykit link state changed")
class StatePersistenceFailed(cause: Throwable) : PrivatePaykitError("Failed to persist private Paykit state", cause)
Expand Down Expand Up @@ -43,12 +44,14 @@ internal data class PrivatePaykitState(
fun cacheState(
cleanupPending: Boolean,
deletedContactCleanupPendingPublicKeys: Set<String>,
profileRecoveryPending: Boolean,
) = PrivatePaykitCacheData(
contacts = contacts.mapNotNull { (publicKey, contactState) ->
(publicKey to contactState.cacheState()).takeIf { contactState.hasCacheState }
}.toMap(),
cleanupPending = cleanupPending,
deletedContactCleanupPendingPublicKeys = deletedContactCleanupPendingPublicKeys,
profileRecoveryPending = profileRecoveryPending,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ internal class PrivatePaykitRecoveryStore(
return true
}

return purgePrivatePaymentStorage(reason)
}

suspend fun purgePrivatePaymentOutboxForProfileRecovery(reason: String): Boolean =
purgePrivatePaymentStorage(reason)

@Suppress("ReturnCount")
private suspend fun purgePrivatePaymentStorage(reason: String): Boolean {
val sessionSecret = keychain.loadString(Keychain.Key.PAYKIT_SESSION.name) ?: return false
if (sessionSecret.isBlank()) return false
val rootPath = PRIVATE_STORAGE_ROOT_PATH.removeSuffix("/")
Expand Down
Loading
Loading